/**
 * All Rights Reserved , Copyright (C) 2020 , 青岛鼎信通讯股份有限公司
 * <p>
 * MpmProjectService 项目立项
 * <p>
 * 修改纪录 2020-12-25 版本：1.0 lanjianwei 创建。
 *
 * @version 版本：1.0
 * @author 作者：lanjianwei 创建日期：2020-12-25
 */
package com.topscomm.mpm.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.exception.MessageException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.Config;
import com.topscomm.basic.util.PrimaryKeyUtil;
import com.topscomm.basic.util.SQLAdapter;
import com.topscomm.cbo.pojo.*;
import com.topscomm.cbo.service.ICboApprovalFlowInsService;
import com.topscomm.cbo.service.ICboApprovalNodeInsService;
import com.topscomm.cbo.service.ICboMessageAppService;
import com.topscomm.cbo.service.ICboMessageSysService;
import com.topscomm.cbo.service.impl.CboUserService;
import com.topscomm.main.hessian.ILtcChanceBackboneService;
import com.topscomm.main.hessian.IMmsDeptExtraInfoService;
import com.topscomm.main.hessian.IMmsProvinceCityMatchinfoService;
import com.topscomm.mis.pojo.MisDeptArchEntity;
import com.topscomm.mis.pojo.MisDeptHeaderEntity;
import com.topscomm.mis.service.IMisDeptArchService;
import com.topscomm.mis.service.IMisDeptHeaderService;
import com.topscomm.mpm.MpmSystemConst;
import com.topscomm.mpm.pojo.*;
import com.topscomm.mpm.service.*;
import com.topscomm.mpm.service.impl.auto.MpmProjectServiceAuto;
import com.topscomm.mpm.utils.ConvertTimeUtil;
import com.topscomm.pub.util.ConvertUtil;
import com.topscomm.pub.util.StringBufferProxy;
import com.topscomm.pub.util.StringUtil;
import com.topscomm.pub.vo.Page;
import com.topscomm.pub.vo.Query;
import com.topscomm.pub.vo.ResponseResult;
import com.topscomm.tap.TapEntity;
import com.topscomm.tap.common.*;
import com.topscomm.tap.threadlocal.ThreadLocalContext;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Service(value = "mpmProjectService")
@Scope(value = "singleton")
public class MpmProjectService extends MpmProjectServiceAuto implements IMpmProjectService {

    @Autowired
    private IMpmProjectMilepostService mpmProjectMilepostService;
    @Autowired
    private IMpmProjectService mpmProjectService;
    @Autowired
    private IMpmProjectTaskService mpmProjectTaskService;
    @Autowired
    private IMpmProjectAppointmentService mpmProjectAppointmentService;
    @Autowired
    private IMpmProjectPlanService mpmProjectPlanService;
    @Autowired
    private IMpmWorkingCalendarService mpmWorkingCalendarService;
    @Autowired
    private ICboApprovalNodeInsService cboApprovalNodeInsService;
    @Autowired
    private ICboMessageAppService cboMessageAppService;
    @Autowired
    private ICboMessageSysService cboMessageSysService;
    @Autowired
    private CboUserService cboUserService;
    @Autowired
    private ICboApprovalFlowInsService cboApprovalFlowInsService;
    @Autowired
    private IMpmProjectProductInfoService mpmProjectProductInfoService;
    @Autowired
    private MpmProjectPolymerizationService mpmProjectPolymerizationService;
    @Autowired
    private MpmProjectProductOutInfoService mpmProjectProductOutInfoService;
    @Autowired
    private MpmDataBoardCustomizeRecordService mpmDataBoardCustomizeRecordService;
    @Autowired
    private IMpmProjectCustomerService mpmProjectCustomerService;
    @Autowired
    private IMmsProvinceCityMatchinfoService mmsProvinceCityMatchinfoService;
    @Autowired
    private IMisDeptArchService misDeptArchService;
    @Autowired
    private MpmProjectBidScoreService mpmProjectBidScoreService;
    @Autowired
    private IMisDeptHeaderService misDeptHeaderService;
    @Autowired
    private MpmProjectRiskService mpmProjectRiskService;
    @Autowired
    private MpmProjectNoMeetWeekService mpmProjectNoMeetWeekService;
    @Autowired
    private IMmsDeptExtraInfoService mmsDeptExtraInfoService;
    @Autowired
    private MpmProjectSaleService mpmProjectSaleService;
    @Autowired
    private ILtcChanceBackboneService ltcChanceBackboneService;
    @Autowired
    private IMpmProjectBidScoreFeedBackService mpmProjectBidScoreFeedBackService;
    @Autowired
    private MpmProjectSuperviseService mpmProjectSuperviseService;

    private static final String PROJECTSOURCETYPE="MpmProjectInfo";
    // 定义早的时间，如果会议结束时间为空，赋值为早的时间，防止compareTo方法报错
    private static final String lastDate = "2099-01-01";

    private Logger logger = LoggerFactory.getLogger(MpmProjectService.class);

    public static final long DAY_MILLSECONDS = 24 * 60 * 60 * 3000L;// 以毫秒为单位，这是三天的意思
    public static final long DAY1_MILLSECONDS = 24 * 60 * 60 * 1000L;// 以毫秒为单位，代表一天
    FlowDatacodeCache flowDatacodeCache = new FlowDatacodeCache();
    DatacodeCache datacodeCache = new DatacodeCache();
    protected List<Map<String, Object>> flowidList = new ArrayList();

    /**
     * @param entity
     * @throws ServiceException
     * @author: lanjianwei
     * @date: 2020-12-25
     * @description:单号生成（已放到beforeSubmit中执行）
     * @modify:
     */
    @Override
    protected void beforeInsert(BasicEntity entity) {
        super.beforeInsert(entity);
        // 赋值Id和单号和项目编号
        if (entity.getId() <= 0) {
            long[] arrayId = PrimaryKeyUtil.GeneIDs(entity.getTableName(), 1);
            entity.setId(arrayId[0]);
            String docNo = String.valueOf(arrayId[0]);
            docNo = docNo.substring(0, 6) + docNo.substring(9);
            entity.setValue(MpmProjectEntity.FieldDocno, docNo);
        }
    }

    @Override
    protected void updateBefore(Map<String, Object> map) throws ServiceException {
        super.updateBefore(map);
        // 数据的projectcode
        String projectcode = ConvertUtil.convertToString(map.get(MpmProjectEntity.FieldProjectcode));
        String mpmState = ConvertUtil.convertToString(map.get(MpmProjectEntity.FieldState));
        // 如果项目处于立项状态,项目等级变更后，需要变更项目编号；否则不允许变更项目编号
        if (projectcode != null && !"".equals(projectcode) && !"9".equals(mpmState)) {
            // 去除春季秋季攻势前缀
            projectcode = projectcode.contains("-") ? projectcode.substring(projectcode.indexOf("-") + 1) : projectcode;
            // replace为去除春季秋季攻势前缀的字符串，项目等级发生变化，修改projectcode等级和后三位编号
            String projectlevel = ConvertUtil.convertToString(map.get("projectlevel"));
            String[] level = {"A", "B", "C", "D"};
            String replace = projectcode;
            // 如果不相等，修改项目等级，并查询projectCode最大的记录在此基础上加一
            if (!level[Integer.parseInt(projectlevel)]
                    .equals(String.valueOf(projectcode.charAt(2)))) {
                // 修改项目等级
                replace = projectcode.replace(String.valueOf(projectcode.charAt(2)),
                        level[Integer.parseInt(projectlevel)]);
                // 查询projectCode最大的记录在此基础上加一
                StringBufferProxy sql = new StringBufferProxy();
                sql.appendSingle(" select projectcode from MpmProject where projectcode like '%{0}%' order by ltrim(ltrim(projectcode, 'QJ-'), 'CJ-') desc ", replace.substring(0,9));
                List<Map<String, Object>> codeList = this.selectExecute(sql.toString());
                String flowCode;
                if (codeList.size() > 0) {
                    String projectcodeTemp = ConvertUtil.convertToString(codeList.get(0).get("projectcode"));
                    flowCode = String.format("%03d", new Integer(projectcodeTemp.substring(projectcodeTemp.length() - 3)) + 1);
                    replace = replace.substring(0,9) + flowCode;
                } else {
                    flowCode = String.format("001");
                    replace = replace.substring(0,9) + flowCode;
                }
            }
            // 增加春季秋季攻势前缀
            if (MpmSystemConst.ProjectAttack.Spring.equals(ConvertUtil.convertToString(map.get("projectattack")))) {
                replace = "CJ-" + replace;
            } else if (MpmSystemConst.ProjectAttack.Autumn.equals(ConvertUtil.convertToString(map.get("projectattack")))) {
                replace = "QJ-" + replace;
            }
            map.put(MpmProjectEntity.FieldProjectcode, replace);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateLevelHistory(Map<String, Object> paraMap) {
        String oldprojectlevel = paraMap.get("oldprojectlevel").toString();
        String newprojectlevel = paraMap.get("newprojectlevel").toString();
        if (StringUtil.isEmpty(oldprojectlevel) || StringUtil.isEmpty(newprojectlevel) || oldprojectlevel.equals(newprojectlevel)) {
            return;
        }
        int oldlevel = Integer.parseInt(oldprojectlevel);
        int newlevel = Integer.parseInt(newprojectlevel);
        JSONObject record = new JSONObject();
        String[] levelArray = {"A", "B", "C", "D"};
        record.put("oldprojectlevel", levelArray[oldlevel]);
        record.put("newprojectlevel", levelArray[newlevel]);
        //更新项目等级变更历史字段
        HashMap<String, Object> updateMap = new HashMap<>();
        updateMap.put("id", paraMap.get("id"));
        updateMap.put("levelhistory", record.toString());
        this.dao.update(updateMap);
    }

    /**
     * @param entity
     * @param sessionUserBean
     * @Title: beforeSubmit
     * @description:
     * @author: lanjianwei
     * @date: 2020年12月30日下午7:45:18
     * @modify:
     */
    @Override
    protected void beforeSubmit(TapEntity entity, SessionUserBean sessionUserBean) {
        super.beforeSubmit(entity, sessionUserBean);
        MpmProjectEntity mpmProjectEntity = (MpmProjectEntity) entity;
        if (StringUtil.isEmpty(mpmProjectEntity.getProjectcode())) {
            // 赋值春季/秋季攻势
            String projectCode = "PS";
            // 赋值项目等级
            String projectLevel = mpmProjectEntity.getProjectlevel();
            projectLevel = datacodeCache
                    .getValueDynamic("MpmProjectLevel", projectLevel, "code", "name");
            SimpleDateFormat sdFormat = new SimpleDateFormat("yyMMdd");
            String dateCode = sdFormat.format(new Date());
            projectCode += projectLevel + dateCode;
            // 查询projectCode最大的记录在此基础上加一
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle(" select projectcode from MpmProject where projectcode like '%{0}%' order by ltrim(ltrim(projectcode, 'QJ-'), 'CJ-') desc ", projectCode);
            List<Map<String, Object>> codeList = this.selectExecute(sql.toString());
            String flowCode;
            if (codeList.size() > 0) {
                String projectcode = ConvertUtil.convertToString(codeList.get(0).get("projectcode"));
                flowCode = String.format("%03d", new Integer(projectcode.substring(projectcode.length() - 3)) + 1);
            } else {
                flowCode = String.format("001");
            }
            projectCode += flowCode;
            if (MpmSystemConst.ProjectAttack.Spring.equals(mpmProjectEntity.getProjectattack())) {
                projectCode = "CJ-" + projectCode;
            } else if (MpmSystemConst.ProjectAttack.Autumn.equals(mpmProjectEntity.getProjectattack())) {
                projectCode = "QJ-" + projectCode;
            }
            mpmProjectEntity.setProjectcode(projectCode);
        }
        this.flowidList = flowDatacodeCache.getApprovalFlowListMap("ApprovalFlow_MpmProject",
            mpmProjectEntity.getUsercode(), "sortcode");
        if (flowidList.size() > 0) {// 赋值审批流程id
            mpmProjectEntity.setFlowid(ConvertUtil.convertToLong(flowidList.get(0).get("id")));
        } else {
            throw new ServiceException("没有匹配的审批流，请联系管理员！");
        }
        // 更新客户信息中的projectcode
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" update MpmProjectCustomer set projectcode = '{0}' where sourcetype = '{1}' and sourceid = {2} ",
                mpmProjectEntity.getProjectcode(), mpmProjectEntity.getTableName(), mpmProjectEntity.getId());
        this.mpmProjectCustomerService.selectExecute(sql.toString());
    }

    @Override
    protected void beforeApprove(TapEntity billEntity, CboApprovalNodeInsEntity nodeIns,
        CboApprovalNodeEntity node, SessionUserBean sessionUserBean) {
        super.beforeApprove(billEntity, nodeIns, node, sessionUserBean);
    }

    /**
     * @author: chengengwei
     * @date: 2021-07-26
     * @description: 执行项目异常状态检测
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeCheckJob() {
        StringBufferProxy sqlWhere = new StringBufferProxy();
        sqlWhere.appendSingle(" projectstate = 1 ");
        // 查询所有正在进行的项目
        List<MpmProjectEntity> mpmProjectEntities = this.queryByWhere(sqlWhere.toString());
        // 遍历检测更新
        mpmProjectEntities.forEach(item -> {
            this.checkProjectAbnormalState(item.getProjectcode());
        });
        sqlWhere.clear();
        sqlWhere.appendSingle(" projectstate in (0,1) ");
        List<MpmProjectEntity> entities = this.queryByWhere(sqlWhere.toString());
        // 最后统一判断项目相关的所有审批流是否在两天之内完成,0411应经营管理部刘元嵩要求，暂时不显示流程超期，后续会修改
        // this.checkOverdueApprovalFlow(entities);

        //把已结项的项目的项目异常状态全部置为正常
        sqlWhere.clear();
        sqlWhere.appendSingle(" projectstate in (2,8) AND ABNORMALSTATE!=0 ");
        List<MpmProjectEntity> MpmProjectEntityList = this.queryByWhere(sqlWhere.toString());
        ArrayList<BasicEntity> entityList = new ArrayList<>();
        if(MpmProjectEntityList.size()>0){
            for(MpmProjectEntity entity:MpmProjectEntityList){
                entity.setAbnormalstate(0);
                entityList.add(entity);
            }
            this.updateBatch(entityList);
        }
    }

    /**
     * @description: 检测、更新项目异常状态，项目异常历史以json字符串的格式保存到abnormalreason字段中
     * [{addDate:2021-01-27,content:'项目超期'}]
     * @param: projectId
     * @return: com.topscomm.pub.vo.ResponseResult<java.lang.Object>
     * @author Administrator
     * @date: 2021/1/27 8:52
     */
    @Override
    public ResponseResult<Object> checkProjectAbnormalState(String projectCode) {
        StringBufferProxy sqlWhere = new StringBufferProxy();
        sqlWhere.appendSingle(" projectcode = '{0}' ", projectCode);
        // 需要更新的项目
        Map<String, Object> updateMap = new HashMap<>();
        // 检测项目是否超期
        List<MpmProjectEntity> mpmProjectEntities = this.queryByWhere(sqlWhere.toString());
        // 如果异常字段的属性值过大，需要删除历史数据，否则无法更新异常字段
        if(!StringUtil.isEmpty(mpmProjectEntities.get(0).getAbnormalreason())
            && mpmProjectEntities.get(0).getAbnormalreason().length() > 1900){
            mpmProjectEntities.get(0).setAbnormalreason("");
        }
        Date currentDate = null;
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
            currentDate = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
        } catch (ParseException pe) {
            pe.printStackTrace();
            throw new MessageException("日期错误，请填写正确格式的日期！");
        }
        if (mpmProjectEntities.size() > 0 && (currentDate.getTime() > mpmProjectEntities.get(0)
            .getPlanenddate().getTime())) {
            updateMap.put("id", mpmProjectEntities.get(0).getId());
//            JSONArray objects = JSONArray.parseArray(mpmProjectEntities.get(0).getAbnormalreason());
//            if (objects == null) {
//                objects = new JSONArray();
//            }
            updateMap.put("abnormalstate", "30");
//            JSONObject reasonObject = new JSONObject();
//            reasonObject.put("updateDate", DateUtil.formatDateTime(new Date()));
//            reasonObject.put("content", "项目超期");
//            objects.add(reasonObject);
            // 属性值过长，超过数据库字段长度
//            updateMap.put("abnormalreason", objects.toJSONString());
            this.update(updateMap);
            return ResponseResult.ok("操作成功，项目超期。");
        }
        // 检测是否有超期里程碑及任务、超期任务
        sqlWhere.clear();
        sqlWhere.appendSingle(" projectcode = '{0}' and planfinishtime<{1}  and milepoststate=0 and ENABLED=1 ",
            projectCode, SQLAdapter.toDateLong(DateUtil.format(new Date(), "yyyy-MM-dd 00:00:00")));
        int overTimeMilepostCount = mpmProjectMilepostService
            .getCount(sqlWhere.toString());// 超期里程碑及任务数量
        if (overTimeMilepostCount > 0) {
            updateMap.put("id", mpmProjectEntities.get(0).getId());
//            JSONArray objects = JSONArray.parseArray(mpmProjectEntities.get(0).getAbnormalreason());
//            if (objects == null) {
//                objects = new JSONArray();
//            }
            updateMap.put("abnormalstate", "20");
//            JSONObject reasonObject = new JSONObject();
//            reasonObject.put("updateDate", DateUtil.formatDateTime(new Date()));
//            reasonObject.put("content", "里程碑及任务超期");
//            objects.add(reasonObject);
            // 属性值过长，超过数据库字段长度
//            updateMap.put("abnormalreason", objects.toJSONString());
            this.update(updateMap);
            return ResponseResult.ok("操作成功，里程碑及任务超期。");
        }

        //检测是否流程超期 MpmProject、MpmProjectAppointment、 MpmProjectPlan
//        if (checkProjectApprovalNodeAbnormalStat(mpmProjectEntities)) {
//            return ResponseResult.ok("操作成功，流程超期。");
//        }

        // 检测是否有超期任务
        sqlWhere.clear();
        sqlWhere.appendSingle(
            " projectcode = '{0}' and planenddate<{1} and state=9 and taskstate in (0,1)",
            projectCode, SQLAdapter.toDateLong(DateUtil.format(new Date(), "yyyy-MM-dd 00:00:00")));
        int overTimeTaskCount = mpmProjectTaskService.getCount(sqlWhere.toString());// 超期里程碑及任务数量
        if (overTimeTaskCount > 0) {
            updateMap.put("id", mpmProjectEntities.get(0).getId());
//            JSONArray objects = JSONArray.parseArray(mpmProjectEntities.get(0).getAbnormalreason());
//            if (objects == null) {
//                objects = new JSONArray();
//            }
            updateMap.put("abnormalstate", "10");
//            JSONObject reasonObject = new JSONObject();
//            reasonObject.put("updateDate", DateUtil.formatDateTime(new Date()));
//            reasonObject.put("content", "任务超期");
//            objects.add(updateMap);
            // 属性值过长，超过数据库字段长度
//            updateMap.put("abnormalreason", objects.toJSONString());
            this.update(updateMap);
            return ResponseResult.ok("操作成功，任务超期");
        }
        updateMap.put("id", mpmProjectEntities.get(0).getId());
//        JSONArray objects = JSONArray.parseArray(mpmProjectEntities.get(0).getAbnormalreason());
//        if (objects == null) {
//            objects = new JSONArray();
//        }
        updateMap.put("abnormalstate", "0");
//        JSONObject reasonObject = new JSONObject();
//        reasonObject.put("updateDate", DateUtil.formatDateTime(new Date()));
//        reasonObject.put("content", "项目状态恢复正常");
//        objects.add(updateMap);
        // 属性值过长，超过数据库字段长度
//        updateMap.put("abnormalreason", objects.toJSONString());
        this.update(updateMap);
        return ResponseResult.ok("操作成功，项目未出现异常");
    }

    /**
     * @author: chengengwei zhangjunyao
     * @date: 2021-07-26 2022-03-25
     * @description: 判断项目相关所有审批流是否有超期的 超期判断取消考虑工作日因素
     * @modify:
     */
    private void checkOverdueApprovalFlow(List<MpmProjectEntity> mpmProjectEntities) {
        // 查询所有状态不为2且不为9并且开始日期小于targetDateString的审批流实例，即所有超期流程
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle("sourcetype like 'MpmProject%' and state != '2' and state != '9' and startdate + 2 < {0}",
                SQLAdapter.toDateShort(DateUtil.formatDate(new Date())));
        List<CboApprovalFlowInsEntity> cboApprovalFlowInsEntities = this.cboApprovalFlowInsService
                .queryByWhere(whereSql.toString());
        if (!cboApprovalFlowInsEntities.isEmpty()) {
            // 修改项目状态
            this.updateAbnormalStateByFlowinds(mpmProjectEntities, cboApprovalFlowInsEntities);
        }
    }

    /**
     * @author: chengengwei
     * @date: 2021-07-26
     * @description: 将所有超期审批流所关联的项目状态置为流程超期
     * @modify:
     */
    private void updateAbnormalStateByFlowinds(List<MpmProjectEntity> mpmProjectEntities,
                                               List<CboApprovalFlowInsEntity> cboApprovalFlowInsEntities) {
        // 将项目实体按照projectcode分组，便于之后查找
        Map<String, List<MpmProjectEntity>> mpmProjectListMap = mpmProjectEntities.stream()
            .filter(map->map.getProjectcode()!=null)
            .collect(Collectors.groupingBy(item -> item.getProjectcode()));
        // 将审批流实例按照sourcetype分组，减少查询次数
        Map<String, List<CboApprovalFlowInsEntity>> flowinsListMap = cboApprovalFlowInsEntities.stream()
                .collect(Collectors.groupingBy(item -> item.getSourcetype()));
        // 所有需要更新异常状态的项目code
        Set<String> projectCodes = new HashSet<>();
        flowinsListMap.forEach((key, value) -> {
            // 根据不同的sourcetype查询不同的表获取项目code
            String sourceids = value.stream().map(map -> ConvertUtil.convertToString(map.getSourceid()))
                    .collect(Collectors.joining(","));
            StringBufferProxy sql = new StringBufferProxy();
            if (MpmProjectChangeEntity.tableName.equals(key)) {
                sql.appendSingle(" select projectcode2 as projectcode from {0} where id in ({1}) ", key, sourceids);
            } else if (MpmProjectTaskFeedbackEntity.tableName.equals(key)) {
                // 先查询项目任务反馈记录，再查询项目任务，获取projectcode
                sql.appendSingle(" select distinct b.projectcode from MpmProjectTaskFeedback a left join " +
                        "MpmProjectTask b on a.taskid = b.id where a.id in ({0}) ", sourceids);
            } else {
                sql.appendSingle(" select projectcode from {0} where id in ({1}) ", key, sourceids);
            }

            List<Map<String, Object>> maps = this.selectExecute(sql.toString());
            maps.forEach(map -> projectCodes.add(ConvertUtil.convertToString(map.get("projectcode"))));
        });
        projectCodes.forEach(item -> {
            if (mpmProjectListMap.get(item) != null && mpmProjectListMap.get(item).size() > 0) {
                MpmProjectEntity mpmProjectEntity = mpmProjectListMap.get(item).get(0);
                // 只更新异常状态为0或10的项目
                if (mpmProjectEntity.getAbnormalstate() == 0 || mpmProjectEntity.getAbnormalstate() == 10) {
                    this.updateAbnormalInfo(mpmProjectEntity);
                }
            }
        });
    }

    /**
     * @author: chengengwei
     * @date: 2021-07-26
     * @description: 更新异常状态和原因
     * @modify:
     */
    private void updateAbnormalInfo(MpmProjectEntity mpmProjectEntity) {
        Map<String, Object> updateMap = new HashMap<>();
        updateMap.put("id", mpmProjectEntity.getId());
//        JSONArray objects = JSONArray.parseArray(mpmProjectEntity.getAbnormalreason());
//        if (objects == null) {
//            objects = new JSONArray();
//        }
        updateMap.put("abnormalstate", "15");
//        JSONObject reasonObject = new JSONObject();
//        reasonObject.put("updateDate", DateUtil.formatDateTime(new Date()));
//        reasonObject.put("content", "流程超期");
//        objects.add(updateMap);
        // 属性值过长，超过数据库字段长度
//        updateMap.put("abnormalreason", objects.toJSONString());
        this.update(updateMap);
    }

    /**
     * @author liuzhenfei
     * @Description 判断 立项、任命、策划流程是否超期
     * @Date 2021/7/1 9:12
     * @Param [cboApprovalNodeInsEntities, mpmProjectEntity]
     * @return boolean
     **/
    private boolean checkProjectApprovalNodeAbnormalStat(
        List<MpmProjectEntity> mpmProjectEntities) {
        StringBufferProxy sqlWhere = new StringBufferProxy();
        //流程集合
        MpmProjectEntity mpmProjectEntity = mpmProjectEntities.get(0);
        String projectCode = mpmProjectEntity.getProjectcode();
        List<CboApprovalNodeInsEntity> cboApprovalNodeInsEntities = new ArrayList<>();
        //如果立项结束时间不为空，则说明立项流程结束，判单是否启动的任命流程，如果未启动，判断是都超过4工作日，满足条件则流程超期
        if (mpmProjectEntity.getFinishdate() != null) {
            sqlWhere.clear();
            sqlWhere.appendSingle(" projectcode = '{0}' order by createon desc ", projectCode);
            List<MpmProjectAppointmentEntity> mpmProjectAppointmentEntities = mpmProjectAppointmentService
                .queryByWhere(sqlWhere.toString());
            if (!CollectionUtils.isEmpty(mpmProjectAppointmentEntities)) {
                // 如果存在任命单据信息，但有可能只是新增的单据，还未提交，需要判断
                sqlWhere.clear();
                //按照创建时间倒序，查询所有的任命流程节点信息
                sqlWhere.appendSingle(
                    "  SOURCETYPE='MpmProjectAppointment'  and SOURCEID='{0}'  and APPROVALUSERID!=0 order by createon desc",
                    mpmProjectAppointmentEntities.get(0).getId());
                cboApprovalNodeInsEntities = cboApprovalNodeInsService
                    .queryByWhere(sqlWhere.toString());
            }
            //如果没有任命流程信息，则说还没开始任命审批，则判断立项结束后是否超过4工作日开启任命流程
            if (CollectionUtils.isEmpty(cboApprovalNodeInsEntities)) {
                if (checkProjectWorkDayAbnormalStat(mpmProjectEntity.getFinishdate(), 4,
                    mpmProjectEntity)) {
                    return true;
                }
            }
            //如果存在任命信息，并且最新的任命信息已经有任命书签发日期，则判断策划流程是否超期
            if (!CollectionUtils.isEmpty(mpmProjectAppointmentEntities)
                && mpmProjectAppointmentEntities.get(0).getSigndate() != null) {
                cboApprovalNodeInsEntities.clear();
                sqlWhere.clear();
                sqlWhere.appendSingle(" projectcode = '{0}' order by createon desc ", projectCode);
                List<MpmProjectPlanEntity> mpmProjectPlanEntities = mpmProjectPlanService
                    .queryByWhere(sqlWhere.toString());
                if (!CollectionUtils.isEmpty(mpmProjectPlanEntities)) {
                    // 如果存在策划单据信息，但有可能只是新增的单据，还未提交，需要判断
                    sqlWhere.clear();
                    //按照创建时间倒序，查询所有的策划流程信息
                    sqlWhere.appendSingle(
                        "  SOURCETYPE='MpmProjectPlan'  and SOURCEID='{0}'  and APPROVALUSERID!=0 order by createon desc",
                        mpmProjectPlanEntities.get(0).getId());
                    cboApprovalNodeInsEntities = cboApprovalNodeInsService
                        .queryByWhere(sqlWhere.toString());
                }

                //如果没有策划流程信息，则说还没开始策划审批，则判断任命签发日期后是否超过7工作日开启策划流程
                if (CollectionUtils.isEmpty(cboApprovalNodeInsEntities)) {
                    if (checkProjectWorkDayAbnormalStat(
                        mpmProjectAppointmentEntities.get(0).getSigndate(), 7, mpmProjectEntity)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * @author liuzhenfei
     * @Description 判断时间（sourceDate）到当前时间相差几个工作日，并跟 days 比较，大于 返回true，否则返回false todo lzf 待实现逻辑
     * @Date 2021/7/1 9:17
     * @Param [sourceDate, days]
     * @return boolean
     **/
    private boolean checkProjectWorkDayAbnormalStat(Date sourceDate, int days,
        MpmProjectEntity mpmProjectEntity) {
        boolean flag = false;
        //判断项目当日与节点日期相差工作日天数
        StringBufferProxy sqlWhere = new StringBufferProxy();
        sqlWhere.appendSingle(" category = '01' and salaryday >= {0}  and  salaryday <= {1}",
            SQLAdapter.toDateLong(DateUtil.format(sourceDate, "yyyy-MM-dd HH:mm:ss")),
            SQLAdapter.toDateLong(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")));
        int workCanlendars = mpmWorkingCalendarService.getCount(sqlWhere.toString());
        flag = workCanlendars > days;
        //流程超期
        if (flag) {
            this.updateAbnormalInfo(mpmProjectEntity);
        }
        return flag;
    }

    /**
     * @author: wudaliang zhangjunyao
     * @date: 2021-07-08 2021-12-14
     * @description: 即将超期项目、里程碑及任务、任务，提前一天进行提醒；评分细则即将超期提醒；评分细则第二次自评提醒
     * @return: com.topscomm.pub.vo.ResponseResult<java.lang.Object>
     * @modify:
     */
    @Override
    @Transactional
    public void willExpireRemind() throws Exception {
            StringBufferProxy sql = new StringBufferProxy();
            // 查询项目状态不是待立项、立项不通过、已结项的
            sql.appendSingle("enabled=1 and projectstate in (0,1) and state=9 and （to_char({0} - 1, 'yyyy-mm-dd')" +
                    "= to_char(SYSDATE, 'yyyy-mm-dd') or to_char({0} - 3, 'yyyy-mm-dd')" +
                    " = to_char(SYSDATE, 'yyyy-mm-dd'))", MpmProjectEntity.FieldPlanenddate);
            List<MpmProjectEntity> overDueProjectEntities = this.queryByWhere(sql.toString());
            List<Map<String, Object>> appMap = new ArrayList<Map<String, Object>>();
            List<Map<String, Object>> sysMap = new ArrayList<Map<String, Object>>();
            // 发送消息内容
            String[] title = {"销售项目超期预警", "销售项目里程碑及任务超期预警", "销售项目任务超期预警"};
            String[] remindContent = {"明天即将超期", "三天后即将超期"};
            String[] remindContent2 = {"请及时登录系统处理","请及时督促里程碑及任务责任人处理","请及时督促任务责任人处理"};
            Date date = new Date();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
            String format = simpleDateFormat.format(date);
            Date currentDate = simpleDateFormat.parse(format);
            if (!CollectionUtils.isEmpty(overDueProjectEntities)) {
                for (MpmProjectEntity overDueProjectEntity : overDueProjectEntities) {
                    Date planEndDate = overDueProjectEntity.getPlanenddate();
                    String dispProjectLevel = datacodeCache.getValueDynamic("MpmProjectLevel", overDueProjectEntity.getProjectlevel(), "code", "name");
                    StringBufferProxy content = new StringBufferProxy();
                    // 若三天后超期则如下配置消息内容
                    if (planEndDate.getTime() - currentDate.getTime() == DAY_MILLSECONDS) {
                        content.appendSingle("【{0}级项目：{1}】{2},{3}", dispProjectLevel, overDueProjectEntity.getProjectname(), remindContent[1], remindContent2[0]);
                    } else {
                        content.appendSingle("【{0}级项目：{1}】{2},{3}", dispProjectLevel, overDueProjectEntity.getProjectname(), remindContent[0], remindContent2[0]);
                    }
                    // 插入App消息
                    Map<String, Object> projectappmap = this.insertMessageApp(overDueProjectEntity.getProjectmanagercode(),
                            title[0], content.toString(), overDueProjectEntity.getId(), PROJECTSOURCETYPE, 0);
                    appMap.add(projectappmap);
                    // 插入系统消息
                    Map<String, Object> projectsysmap = this.insertMessageSys(overDueProjectEntity.getProjectmanagercode(),
                            overDueProjectEntity.getProjectmanager(), title[0], content.toString(), overDueProjectEntity.getId(), PROJECTSOURCETYPE);
                    sysMap.add(projectsysmap);
                }
            }
            // 查询是否即将里程碑及任务超期
            sql.clear();
            sql.appendSingle(" milepoststate = 0 and enabled = 1 and (to_char({0} - 1, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd')" +
                            " or to_char({0} - 3, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd'))",
                    MpmProjectMilepostEntity.FieldPlanfinishtime);
            List<MpmProjectMilepostEntity> overDueProjectMilepostEntities = mpmProjectMilepostService.queryByWhere(sql.toString());
            if (!CollectionUtils.isEmpty(overDueProjectMilepostEntities)) {
                // 查询里程碑及任务对应项目
                String projectCodes = overDueProjectMilepostEntities.stream().map(entity -> entity.getProjectcode())
                        .collect(Collectors.joining("','", "'", "'"));
                sql.clear();
                sql.appendSingle("projectcode in ({0})", projectCodes);
                List<MpmProjectEntity> projectEntities = this.queryByWhere(sql.toString());
                Map<String, MpmProjectEntity> projectMap = projectEntities.stream().collect(Collectors.toMap(
                        MpmProjectEntity::getProjectcode, item -> item, (v1, v2) -> v1));
                // 遍历里程碑及任务，将里程碑及任务即将超期消息发送给里程碑及任务责任人，如果项目经理和里程碑及任务责任人不为同一人，则给项目经理发消息
                for (MpmProjectMilepostEntity overDueProjectMilepostEntity : overDueProjectMilepostEntities) {
                    Date planFinishDate = overDueProjectMilepostEntity.getPlanfinishtime();
                    String dispProjectLevel = datacodeCache.getValueDynamic("MpmProjectLevel", projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getProjectlevel(),"code", "name");
                    String projectname =  projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getProjectname();
                    StringBufferProxy milepostcontent = new StringBufferProxy();
                    // 若三天后超期则如下配置消息内容
                    if (planFinishDate.getTime() - currentDate.getTime() == DAY_MILLSECONDS) {
                        milepostcontent.appendSingle("【{0}级项目：{1}】里程碑及任务：“{2}”，{3}，", dispProjectLevel, projectname, overDueProjectMilepostEntity.getMilepostname(), remindContent[1]);
                    } else {
                        milepostcontent.appendSingle("【{0}级项目：{1}】里程碑及任务：“{2}”，{3}，", dispProjectLevel, projectname, overDueProjectMilepostEntity.getMilepostname(), remindContent[0]);
                    }
                    String milepostStr = milepostcontent.toString() + remindContent2[0];
                    // 插入App消息
                    Map<String, Object> milepostappmap = this.insertMessageApp(overDueProjectMilepostEntity.getResponsiblecode(),
                            title[1], milepostStr, projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getId(), MpmProjectMilepostEntity.tableName,
                            0);
                    appMap.add(milepostappmap);
                    // 插入系统消息
                    Map<String, Object> mielpostsysmap = this.insertMessageSys(overDueProjectMilepostEntity.getResponsiblecode(),
                            overDueProjectMilepostEntity.getResponsible(), title[1], milepostStr,
                            projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getId(), MpmProjectMilepostEntity.tableName);
                    sysMap.add(mielpostsysmap);
                    // 里程碑及任务超期提前一天通知项目经理
                    if (!overDueProjectMilepostEntity.getResponsiblecode().equals(projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getProjectmanagercode())) {
                        this.overdueMilepostRemindPM(overDueProjectMilepostEntity, projectMap, appMap, sysMap, milepostcontent, title, remindContent2);
                    }
                }
            }
            // 查询是否即将任务超期(任务下发且任务状态为未开始、进行中)
            sql.clear();
            sql.appendSingle(" state = 9 and taskstate in (0,1) and enabled=1 and (to_char({0} - 1, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd')" +
                            " or to_char({0} - 3, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd'))",
                    MpmProjectTaskEntity.FieldPlanenddate);
            List<MpmProjectTaskEntity> overDueProjectTaskEntities = mpmProjectTaskService.queryByWhere(sql.toString());
            if (!CollectionUtils.isEmpty(overDueProjectTaskEntities)) {
                // 查询里程碑及任务对应项目
                String projectCodes = overDueProjectTaskEntities.stream().map(entity -> entity.getProjectcode())
                        .collect(Collectors.joining("','", "'", "'"));
                sql.clear();
                sql.appendSingle("projectcode in ({0})", projectCodes);
                List<MpmProjectEntity> projectEntities = this.queryByWhere(sql.toString());
                Map<String, MpmProjectEntity> projectMap = projectEntities.stream().collect(Collectors.toMap(
                        MpmProjectEntity::getProjectcode, mpmProjectEntity -> mpmProjectEntity, (v1, v2) -> v1));
                for (MpmProjectTaskEntity overDueProjectTaskEntity : overDueProjectTaskEntities) {
                    Date planEndDate = overDueProjectTaskEntity.getPlanenddate();
                    String taskResponsibleCode = overDueProjectTaskEntity.getResponsiblecode();
                    MpmProjectEntity projectEntity = projectMap.get(overDueProjectTaskEntity.getProjectcode());
                    String dispProjectLevel = datacodeCache.getValueDynamic("MpmProjectLevel", projectEntity.getProjectlevel(), "code", "name");
                    long mpmId = projectEntity.getId();
                    StringBufferProxy taskcontent = new StringBufferProxy();
                    // 若三天后超期则如下配置消息内容
                    if (planEndDate.getTime() - currentDate.getTime() == DAY_MILLSECONDS) {
                        taskcontent.appendSingle("【{0}级项目：{1}】任务：“{2}”，{3}，", dispProjectLevel, projectEntity.getProjectname(), overDueProjectTaskEntity.getTaskname(), remindContent[1]);
                    } else {
                        taskcontent.appendSingle("【{0}级项目：{1}】任务：“{2}”，{3}，", dispProjectLevel, projectEntity.getProjectname(), overDueProjectTaskEntity.getTaskname(), remindContent[0]);
                    }
                    String taskcontentRes = taskcontent.toString() + remindContent2[0];
                    // 通知任务负责人
                    Map<String, Object> taskappmap = this.insertMessageApp(taskResponsibleCode,
                            title[2], taskcontentRes, mpmId, MpmProjectTaskEntity.tableName, 0);
                    appMap.add(taskappmap);
                    // 插入系统消息
                    Map<String, Object> tasksysmap = this.insertMessageSys(taskResponsibleCode,
                            overDueProjectTaskEntity.getResponsible(), title[2], taskcontentRes, mpmId,
                            MpmProjectTaskEntity.tableName);
                    sysMap.add(tasksysmap);
                    // 通知项目经理
                    if (!taskResponsibleCode.equals(projectEntity.getProjectmanagercode())) {
                        String taskcontentProject = taskcontent.toString() + remindContent2[2];
                        taskappmap = this.insertMessageApp(projectEntity.getProjectmanagercode(), title[2], taskcontentProject,
                                mpmId, MpmProjectTaskEntity.tableName, 0);
                        appMap.add(taskappmap);
                        tasksysmap = this.insertMessageSys(projectEntity.getProjectmanagercode(), projectEntity.getProjectmanager(),
                                title[2], taskcontentProject, mpmId, MpmProjectTaskEntity.tableName);
                        sysMap.add(tasksysmap);
                    }
                }
            }
            // 查询评分细则是否即将超期（三天/一天）
            this.bidScoreSoonOverdue(appMap, sysMap);
            // 省招A级项目，挂网日期之后，提醒项目经理发送第二次自评提醒
            this.sendSecondBidScoreAlert(appMap, sysMap);
            // 任务更新时间前一天对任务责任人发送更新提醒
            mpmProjectTaskService.sendTaskUpdateFreApp(appMap, sysMap);
            cboMessageAppService.insertList(appMap);
            cboMessageSysService.insertList(sysMap);
    }

    /**
     * @author: wudaliang
     * @date: 2021-07-08
     * @description: 插入App消息
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     * @modify:
     */
    public Map<String, Object> insertMessageApp(String usercode,String extendfield1,String content,long sourceid,String sourcetype,int sendtype) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("usercode", usercode);
        map.put("extendfield1", extendfield1);
        map.put("content", content);
        map.put("sourceid", sourceid);
        map.put("sourcetype", sourcetype);
        map.put("sendtype", sendtype);
        return map;
    }

    /**
     * @author: wudaliang
     * @date: 2021-07-08
     * @description: 插入系统消息
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     * @modify:
     */
    public Map<String, Object> insertMessageSys(String receivercode,String receivername,String subject,String content,long sourceid,String sourcetype) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("receivercode", receivercode);
        map.put("receivername", receivername);
        map.put("subject", subject);
        map.put("content", content);
        map.put("sourceid", sourceid);
        map.put("sourcetype", sourcetype);
        return map;
    }
    @Override
    public void setDispFields(Map<String, Object> mapRow, DatacodeCache datacodeCache) {
        super.setDispFields(mapRow,datacodeCache);
        String temp;
        if (mapRow.get("projectmanagercode") != null) {
            temp = mapRow.get("projectmanagercode").toString();
            mapRow.put("dispprojectmanagercode", datacodeCache.getValueDynamic("CboUser", temp, "code", "name"));
        }
        // 拼接字符串 项目经理[项目经理工号] 部门
        if(mapRow.get("projectmanagercode") != null && mapRow.get("deptname") != null)
        {
            temp = mapRow.get("projectmanagercode").toString();
            mapRow.put("dispprojectmanagercodeanddeptname", datacodeCache.getValueDynamic("CboUser", temp, "code", "name")+"["
            + temp + "]-" + mapRow.get("deptname").toString());
        }
        // 拼接字符串 计划开始日期-计划结束日期
        if(mapRow.get("planstartdate") != null && mapRow.get("planenddate") != null)
        {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String planstartdate = simpleDateFormat.format(mapRow.get("planstartdate"));
            String planenddate = simpleDateFormat.format(mapRow.get("planenddate"));
            mapRow.put("planstartdateandplanenddate", planstartdate + "至" + planenddate);
        }
        // 拼接字符串 决策组成员工号
        if (mapRow.get("decisionusercode") != null) {
            temp = ConvertUtil.convertToString(mapRow.get("decisionusercode"));
            if (temp.length() > 2) {
                mapRow.put("cutdecisionusercode", temp.substring(1, temp.length() - 1));
            }
        }
        // 拼接字符串 督办情况
        if(mapRow.get("supervisecodelist") != null && mapRow.get("supervisestatelist") != null) {
            StringBuffer stringBuffer = new StringBuffer();
            String[] supervisecodesplit = mapRow.get("supervisecodelist").toString().split(",");
            String[] supervisestatesplit = mapRow.get("supervisestatelist").toString().split(",");
            if(supervisecodesplit.length>3) {
                for(int i=0;i<3;i++) {
                    stringBuffer.append(supervisecodesplit[i] + "[" + datacodeCache.getValueDynamic("MpmSuperviseState", supervisestatesplit[i], "code", "name") + "]\n");
                }
                stringBuffer.append("...\n");
            } else {
                for (int i = 0; i < supervisecodesplit.length; i++) {
                    stringBuffer.append(supervisecodesplit[i] + "[" + datacodeCache.getValueDynamic("MpmSuperviseState", supervisestatesplit[i], "code", "name") + "]\n");
                }
            }
            String str = stringBuffer.toString();
            str = str.substring(0,str.length()-1);
            mapRow.put("superviselist", str);
        }
        if (mapRow.get("deptname1") != null) {
            String temp1 = ConvertUtil.convertToString(mapRow.get("deptname1"));
            String temp2 = ConvertUtil.convertToString(mapRow.get("deptname2"));
            String temp3 = ConvertUtil.convertToString(mapRow.get("deptname3"));
            String dispdeptname = this.mmsProvinceCityMatchinfoService.getDispdeptname(temp1, temp2, temp3);
            mapRow.put("dispdeptname", dispdeptname);
        } else {
            mapRow.put("dispdeptname", "");
        }
        if (mapRow.get("deptcommoncode") != null) {
            temp = mapRow.get("deptcommoncode").toString();
            mapRow.put("dispdeptcommoncode", datacodeCache.getValueDynamic("DeptCommonCodeTrack", temp, "code", "name"));
        }
    }

    /**
     * @author: chengengwei
     * @date: 2021-08-25
     * @description: 按产品线统计
     * @modify:
     */
    @Override
    public List<Map<String, Object>> getProductLineSummaryList(String whereSql) throws Exception {
        Map<String, Object> paramMap = new HashMap<>();
        List<Map<String, Object>> summaryList = this.queryMapByWhere(whereSql, "getProductLineSummaryList");
        if (summaryList.size() > 0) {
            for (Map<String, Object> summaryMap : summaryList) {
                summaryMap.put(MpmProjectProductInfoEntity.FieldProductlinename, datacodeCache.getValueDynamic("ProductLine", ConvertUtil.convertToString(summaryMap.get("productlinecode")), "code", "name"));
                summaryMap.remove(MpmProjectProductInfoEntity.FieldProductlinecode);
            }
            // 获取key集
            Set<String> fieldsSet = summaryList.get(0).keySet();
            // 合计map
            Map<String, Object> totalMap = new HashMap<>();
            // 初始化值
            fieldsSet.forEach(field -> {
                if (MpmProjectProductInfoEntity.FieldProductlinename.equals(field)) {
                    totalMap.put(field, "合计");
                } else {
                    totalMap.put(field, new BigDecimal(0));
                }
            });
            // 合计map计算每个字段之和
            summaryList.forEach(map -> {
                fieldsSet.forEach(field -> {
                    if (!MpmProjectProductInfoEntity.FieldProductlinename.equals(field)) {
                        // 每条记录该字段值
                        BigDecimal fieldValue = ConvertUtil.convertToBigDecimal(map.get(field));
                        // 合计记录该字段值
                        BigDecimal totalValue = ConvertUtil.convertToBigDecimal(totalMap.get(field));
                        totalMap.put(field, totalValue.add(fieldValue));
                    }
                });
                // 处理未关联产品线的记录
                if (StringUtil.isEmpty(ConvertUtil.convertToString(map.get("productlinename")))) {
                    map.put("productlinename", "未关联产品线");
                }
            });
            // 获取所有的产品线信息
            List<Map> allProductLine = (List<Map>) this.getAllProductLine();
            // summaryList按产品线名称分组
            Map<Object, List<Map>> summaryListGroupMap = summaryList.stream().collect(Collectors
                    .groupingBy(item -> item.get("productlinename")));
            // 统计结果没有在allProductLineGroupMap中的需要置0
            allProductLine.forEach(map -> {
                // 若统计数据中不包括该产品线则创建一条记录
                String projectLineName = ConvertUtil.convertToString(map.get("NAME"));
                if (summaryListGroupMap.get(projectLineName) == null) {
                    Map<String, Object> newRecord = new HashMap<>();
                    fieldsSet.forEach(field -> {
                        if (MpmProjectProductInfoEntity.FieldProductlinename.equals(field)) {
                            newRecord.put(field, projectLineName);
                        } else {
                            newRecord.put(field, new BigDecimal(0));
                        }
                    });
                    summaryList.add(newRecord);
                }
            });
            // 最后添加合计记录
            summaryList.add(totalMap);
        }
        return summaryList;
    }

    /**
     * @author: chengengwei
     * @date: 2021-09-01
     * @description: 查询所有产品线信息
     * @modify:
     * @return
     */
    private List<? extends Map> getAllProductLine() throws Exception {
        // 查询本地数据库获取机会点信息
        if ("1".equals(ParameterCache.getValue("MPMQueryLTCByLocal"))) {
            return this.queryMap(null, "queryAllProductLine");
        } else {
            // 通过数据服务平台查询
            SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            requestFactory.setConnectTimeout(2000);// 设置超时
            requestFactory.setReadTimeout(100000);// 读取超时时间
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            String token = ParameterCache.getValue("MPM_Token");
            String templateid = ParameterCache.getValue(MpmSystemConst.MPM_Query_AllProductLine);
            headers.set("token", token);
            JSONObject map = new JSONObject();
            map.put("templateid", templateid);
            String url = ParameterCache.getValue("MPM_QueryUrl");
            JSONObject params = new JSONObject();
            map.put("paramsMap", params);
            // 设置分页查询
            map.put("pageNum", 1);
            map.put("pageSize", 100);

            HttpEntity<JSONObject> request = new HttpEntity<>(map, headers);
            ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class);

            if (response.getBody().getBooleanValue("success") == true) {
                JSONArray dataList = response.getBody().getJSONObject("result").getJSONArray("dataList");
                List<Map> list = JSONObject.parseArray(dataList.toJSONString(), Map.class);
                return list;
            } else {
                throw new Exception("保存信息失败，请联系管理员！");
            }
        }
    }

    @Override
    @Transactional
    public int updateRemindTime(String id) {
        if (StringUtil.isEmpty(id)) {
            return 0;
        }
        Map<String, Object> mpmProject = this.queryMapById(id);
        Date now = new Date();
        mpmProject.put(MpmProjectEntity.FieldReminddate, now);
        mpmProject.put(MpmProjectEntity.FieldModifiedon, now);
        return this.update(mpmProject);
    }

    /**
     * @author: chengengwei
     * @date: 2021-11-01
     * @description: 获取权限SQL
     * @modify:
     * @return
     */
    @Override
    public String getPermissionSQL(Map<String, Object> paramMap) {
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("noLoginUser", "1");
        queryParam.put("usercodefromrpc", ConvertUtil.convertToString(paramMap.get("usercode")));
        return mpmProjectPolymerizationService.existsSqlForQuery(queryParam, "MPMPROJECT", "PROJECTCODE");
    }
    /**
     * @author zhangjunyao
     * @Description 给项目经理发送取消审批权限开放的消息
     * @Date 2021/11/19
     * @Param cboApprovalNodeInsEntities
     * @return
     **/
    @Transactional
    public void sendMessageToManager(CboApprovalNodeInsEntity nodeIns) {
        String sourceid = ConvertUtil.convertToString(nodeIns.getSourceid());
        String sourcetye = nodeIns.getSourcetype();
        // 查询项目经理、审批人
        MpmProjectEntity projectEntity = this.queryById(sourceid);
        CboUserEntity user = cboUserService.queryById(ConvertUtil.convertToString(nodeIns.getModifieduser()));
        // 消息标题和内容
        String title = "【" + projectEntity.getProjectname() + "项目】";
        String content = "【" + projectEntity.getProjectname() + "项目】：" + "在" + nodeIns.getExtendfield2() + "节点中，审批人" +
                user.getName() + "不同意此项目审批通过。您可前往立项详情页选择“取消审批”。";
        // 发送消息
        // 系统消息
        Map<String, Object> sysMessage = insertMessageSys(projectEntity.getProjectmanagercode(), projectEntity.getProjectmanager(),
                title, content, nodeIns.getSourceid(), sourcetye);
        cboMessageSysService.insertMap(sysMessage);
        // App消息
        Map<String, Object> appMessage = insertMessageApp(projectEntity.getProjectmanagercode(), title, content,
                nodeIns.getSourceid(), sourcetye, 0);
        cboMessageAppService.insertMap(appMessage);
    }

    /**
     * @author zhangjunyao
     * @Description 判断项目在决策组审批节点是否有被退回
     * @Date 2021/11/19
     * @Param project.projectcode
     * @return boolean
     **/
    public boolean ifApprovalBack(Map<String, Object> paraMap) {
        boolean isBack = false;
        // 获取项目信息
        if (!paraMap.containsKey("projectcode")) {
            return isBack;
        }
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" projectcode = '{0}' ", ConvertUtil.convertToString(paraMap.get("projectcode")));
        MpmProjectEntity projectEntity = this.queryObjectByWhere(sql.toString());
        if (ObjectUtils.isEmpty(projectEntity)) {
            return isBack;
        }
        String sourceId = ConvertUtil.convertToString(projectEntity.getId());
        sql.clear();
        // 查询是否存在退回状态的决策组审批节点信息
        sql.appendSingle(" nodeid = (select id from {0} where {1} like '%ifApprovalBack%') and sourceid = '{2}' and" +
                        " sourcetype = '{3}' and state = '3' ", CboApprovalNodeEntity.tableName,
                CboApprovalNodeEntity.FieldApprovalparam, sourceId, MpmProjectEntity.tableName);
        List<CboApprovalNodeInsEntity> nodeInsEntities = cboApprovalNodeInsService.queryByWhere(sql.toString());
        if (!CollectionUtils.isEmpty(nodeInsEntities)) {
            isBack = true;
        }
        return isBack;
    }
    /**
     * @author houyuhang
     * @Description 首页信息概览内容
     * @Date 2021/11/29
     * @return List<Map<String,Object>>
     **/
    @Override
    public List<Map<String,Object>> queryOverdueInfo(Map<String, Object> paraMap) {
        List<Map<String, Object>> resultMapList = new ArrayList<>();
        // 查询任命待办数量
        resultMapList.add(mpmProjectAppointmentService.queryBacklogAppointment(paraMap));
        // 查询策划待办数量
        resultMapList.add(mpmProjectPlanService.queryBacklogPlan(paraMap));
        // 查询超期项目数量
        resultMapList.add(queryOverdueProject(paraMap));
        // 查询超期历程碑数量
        resultMapList.add(mpmProjectMilepostService.queryOverdueMilepost(paraMap));
        // 查询超期任务数量
        resultMapList.add(mpmProjectTaskService.queryOverdueTask(paraMap));
        // 查询任命超期数量
        resultMapList.add(mpmProjectAppointmentService.queryOverdueAppointment(paraMap));
        // 查询策划超期数量
        resultMapList.add(mpmProjectPlanService.queryOverduePlan(paraMap));
        return resultMapList;
    }
    /**
     * @author houyuhang
     * @Description 查询超期项目数量
     * @Date 2021/11/29
     * @return Map<String,Object>
     **/
    public Map<String,Object> queryOverdueProject(Map<String, Object> paraMap) {
        Map<String, Object> overdueProjectResult = new HashMap<>();
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" MpmProject.ABNORMALSTATE = '{0}' and MpmProject.projectstate= '{1}' and MpmProject.enabled = 1 ",
                MpmSystemConst.AbnormalStateCode.OverdueProjectCode,MpmSystemConst.ExecuteStateCode);
        sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(MpmProjectEntity.tableName,
                MpmProjectEntity.FieldProjectcode, ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
        int countProject = this.getCount(sql.toString());
        overdueProjectResult.put("code", "overdueProjectNum");
        overdueProjectResult.put("name", "超期项目");
        overdueProjectResult.put("iconImg", "/static/images/paojectManager/overdueProject.png");
        overdueProjectResult.put("value", countProject);
        return overdueProjectResult;
    }
    /**
     * @description: 专用于生成首页查询关联MPMPROJECT表的exist语句
     * @param: tableNam 要查询的表名称
     * @param: column 要查询的表名称和MPMPROJECT表的projectcode关联字段名称
     * @param: permissionFlage 权限标识（org：公司数据，inChargeMe：我负责的，participate：我参与的）
     * @return: java.lang.String
     * @author Administrator
     * @date: 2021/1/7 18:33
     */
    public String whereExistsSqlForIndex(String tableNam, String column, String permissionFlage) {
        StringBufferProxy sql = new StringBufferProxy();

        // 公司数据
        if ("org".equals(permissionFlage)) {
            // 如果是公司数据，则查询
            sql.appendSingle(this.spellSqlForDataBoard(new HashMap<>(),tableNam, column));
        } else if ("inChargeMe".equals(permissionFlage)) {
            // 我负责的（项目经理是我）
            sql.appendSingle(" EXISTS (SELECT id FROM MPMPROJECT existProject WHERE existProject.PROJECTCODE =  {0}.{1} and existProject.PROJECTMANAGERCODE='{2}'  )", tableNam, column, this.getUserBean().getUser().getCode());
        } else if ("participate".equals(permissionFlage)) {
            // 我参与的（项目组成员中有我）
            sql.appendSingle(" EXISTS (SELECT id FROM MPMPROJECT existProject WHERE existProject.PROJECTCODE = {0}.{1} and EXISTS (SELECT PROJECTCODE FROM MPMPROJECTTEAM MPMPROJECTTEAM WHERE existProject.PROJECTCODE = MPMPROJECTTEAM.PROJECTCODE AND MPMPROJECTTEAM.USERCODE = '{2}' AND MPMPROJECTTEAM.STATE = 9  AND MPMPROJECTTEAM.ENABLED = 1)  )", tableNam, column, this.getUserBean().getUser().getCode());
        }
        return sql.toString();
    }
    /**
     * @description: 首页数据看板、手机端首页的where条件拼接通用方法
     * @param: paraMap
     * @return: java.util.List<com.topscomm.mpm.pojo.MpmProjectEntity>
     * @author Administrator
     * @date: 2021/1/7 18:28
     */
    public String spellSqlForDataBoard(Map<String, Object> paraMap, String tableName, String columnName) {
        StringBufferProxy sql = new StringBufferProxy();
        // 如果是超期里程碑、任务，需要拼接exists语句
        if (MpmProjectEntity.tableName.equals(tableName)) {
            sql.appendSingle(" ( {0}.enabled = 1 ", MpmProjectEntity.tableName);
        } else {
            sql.appendSingle(" exists ( select PROJECTCODE from MPMPROJECT where enabled = 1 and {0}.{1} = mpmproject.projectcode ", tableName, columnName);
        }
        if (paraMap.containsKey("deptname")) {
            String value = ConvertUtil.convertToString(paraMap.get("deptname"));
            sql.appendSingle("AND EXISTS ( SELECT cbodept.code FROM cbodept WHERE mpmproject.deptcode = cbodept.CODE and cbodept.FULLNAME LIKE '%{0}%' ) ", value);
        }
        if (paraMap.containsKey("qry_deptcommoncode")) {
            String value = paraMap.get("qry_deptcommoncode").toString();
            if (!StringUtil.isEmpty(value))
                sql.appendSingle(" and mpmproject.deptcommoncode in ({0}) ", value);
        }
        if (paraMap.containsKey("projectname")) {
            String value = ConvertUtil.convertToString(paraMap.get("projectname"));
            sql.appendSingle("AND mpmproject.projectname like '%{0}%'  ", value);
        }
        if (paraMap.containsKey("projectstate")) {
            String value = ConvertUtil.convertToString(paraMap.get("projectstate"));
            sql.appendSingle("AND mpmproject.projectstate ='{0}'  ", value);
        }
        if (paraMap.containsKey("query_projectlevel")) {
            String value = ConvertUtil.convertToString(paraMap.get("query_projectlevel"));
            sql.appendSingle("AND mpmproject.PROJECTLEVEL in ({0})  ", value);
        }
        if (paraMap.containsKey("abnormalstate")) {
            String value = ConvertUtil.convertToString(paraMap.get("abnormalstate"));
            sql.appendSingle("AND mpmproject.abnormalstate ='{0}'  ", value);
        }

        if (paraMap.containsKey("projectmanager")) {
            String value = ConvertUtil.convertToString(paraMap.get("projectmanager"));
            sql.appendSingle("AND (mpmproject.projectmanager  like '%{0}%' or mpmproject.projectmanagercode  like '%{0}%' ) ", value);
        }
        if (paraMap.containsKey("sponsor")) {
            String value = ConvertUtil.convertToString(paraMap.get("sponsor"));
            sql.appendSingle("AND (mpmproject.sponsor  like '%{0}%' or mpmproject.sponsorcode  like '%{0}%' ) ", value);
        }
        if (paraMap.containsKey("owner")) {
            String value = ConvertUtil.convertToString(paraMap.get("owner"));
            sql.appendSingle("AND (mpmproject.owner  like '%{0}%' or mpmproject.owner  like '%{0}%' ) ", value);
        }
        if (paraMap.containsKey("startDateForFinisthDate")) {
            String value = ConvertUtil.convertToString(paraMap.get("startDateForFinisthDate"));
            sql.appendSingle(" and  mpmproject.finishDate > {0}", SQLAdapter.toDateShort(value));
        }
        if (paraMap.containsKey("endDaterFinisthDate")) {
            String value = ConvertUtil.convertToString(paraMap.get("endDaterFinisthDate"));
            sql.appendSingle("  and  mpmproject.finishDate < {0}", SQLAdapter.toDateShort(value) + " + 1");
        }
        if (paraMap.containsKey("startDateForActualEndDate")) {
            String value = ConvertUtil.convertToString(paraMap.get("startDateForActualEndDate"));
            sql.appendSingle("  and  mpmproject.actualenddate > {0}", SQLAdapter.toDateShort(value));
        }
        if (paraMap.containsKey("endDateForActualEndDate")) {
            String value = ConvertUtil.convertToString(paraMap.get("endDateForActualEndDate"));
            sql.appendSingle(" and  mpmproject.actualenddate < {0}", SQLAdapter.toDateShort(value));
        }
        if (paraMap.containsKey("projectState")) {
            String value = ConvertUtil.convertToString(paraMap.get("projectState"));
            sql.appendSingle("AND mpmproject.projectState = {0} ", value);
        }
        // 春季/秋季攻势筛选条件
        if (paraMap.containsKey("qry_projectattack")) {
            String value = ConvertUtil.convertToString(paraMap.get("qry_projectattack"));
            if (!StringUtil.isEmpty(value)) {
                sql.appendSingle(" and {0} in ({1}) ", SQLAdapter.isNull(MpmProjectEntity.tableName + "." + MpmProjectEntity.FieldProjectattack, "0"), value);
            }
        }
        // 管理员、超级管理员，不控制权限
        if (this.getUserBean().getUser().getAdminlevel() < 1) {
            String value = this.getUserBean().getUser().getCode();
            sql.appendSingle(" and (EXISTS (SELECT PROJECTCODE FROM MPMPROJECTSTAKEHOLDER STACKHOLDER WHERE STACKHOLDER.enabled = '1' and STACKHOLDER.USERCODE = '{0}' AND {1}.{2} = STACKHOLDER.PROJECTCODE) or mpmproject.projectmanagercode = '{0}' or mpmproject.usercode = '{0}' ",
                    value, MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode);
            // 根据用户Code在deptExtraInfo表中找到自己作为省总或者财总的省份
            String userCode = this.getUserBean().getUser().getCode();
            List<String> deptCommonCodes = mmsDeptExtraInfoService.getDeptCommonCodes(userCode);
            String commonCodes = StringUtils.join(deptCommonCodes.toArray(), ",");
            if (!ObjectUtil.isEmpty(commonCodes)) {
                sql.appendSingle(" OR mpmproject.deptcommoncode IN ({0})", commonCodes);
            }
            // 用户数据权限
            String dataPession = this.getDataPermission(TapSystemConst.TapOperationTypeEnum.Select, "", this.getUserBean());
            if (StringUtil.isEmpty(dataPession)) {
                sql.appendSingle(" ) ");
            } else {
                sql.appendSingle(" or {0}) ", dataPession);
            }
        }
        sql.appendSingle(" ) ");
        return sql.toString();
    }
    /**
     * @author: wudaliang
     * @date: 2021-03-09
     * @description: 获取当前登录用户
     * @return: com.topscomm.tap.common.SessionUserBean
     * @modify:
     */
    public SessionUserBean getUserBean() {
        return (SessionUserBean) ThreadLocalContext.sessionUserBeanThreadLocal.get();
    }
    /**
     * @author: houyuhang
     * @date: 2021-11-30
     * @description: 获取即将超期的任务
     * @return: List<Map<String,Object>>
     * @modify:
     */
    public List<Map<String,Object>> querySoonOverdueTask(Map<String,Object> paraMap) {
        DateTime dateTime = DateUtil.offsetDay(new Date(), ConvertUtil.convertToInt(paraMap.get("overdueDays")));// 获取N天后的时间
        StringBufferProxy sql = new StringBufferProxy();
        // 获取计划结束时间在今天和3天/一周之间，且已下发但是未开始或进行中的任务
        sql.appendSingle(" MpmProjectTask.PLANENDDATE BETWEEN {0} and {1} and MpmProjectTask.TASKSTATE in ('{2}','{3}') AND MpmProjectTask.STATE=9 ",
                SQLAdapter.toDateShort(DateUtil.format(new Date(), "yyyy-MM-dd")),
                SQLAdapter.toDateShort(DateUtil.format(dateTime, "yyyy-MM-dd")),
                MpmSystemConst.TaskStateCode.TaskNotStartCode,MpmSystemConst.TaskStateCode.TaskIncompleteCode);
        sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(MpmProjectTaskEntity.tableName, MpmProjectTaskEntity.FieldProjectcode,
                ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
        List<Map<String, Object>> list = mpmProjectTaskService.queryMapForPage(sql.toString(), 1,
                ConvertUtil.convertToInt(paraMap.get("pageSize")), ConvertUtil.convertToString(paraMap.get("sidx")),
                ConvertUtil.convertToString(paraMap.get("sord")), "queryMapForPageForIndex");
        sql.clear();
        // 向所有任务中添加所属项目的deptname
        String projectCodes = list.stream().map(e->ConvertUtil.convertToString(e.get("projectcode"))).collect(Collectors.joining("','","'","'"));
        List<String> queryFileds = new ArrayList<>();
        queryFileds.add(MpmProjectEntity.FieldProjectcode);
        queryFileds.add(MpmProjectEntity.FieldDeptname);
        List<Map<String,Object>> deptList = this.mpmProjectService.queryMapFieldsByWhere("projectcode in ("+projectCodes+")",queryFileds);
        Map<String, String> deptMap = deptList.stream().collect(Collectors.toMap(e->ConvertUtil.convertToString(e.get("projectcode")),e->ConvertUtil.convertToString(e.get("deptname"))));
        list.forEach(temp->{
            temp.put("deptname",deptMap.get(temp.get("projectcode")));
        });
        return list;
    }
    /**
     * @author: houyuhang
     * @date: 2021-11-30
     * @description: 获取最新创建和近期完成的项目
     * @return: List<Map<String,Object>>
     * @modify:
     */
    public List<Map<String,Object>> queryRecentlyCreateOrComplete(Map<String,Object> paraMap) {
        DateTime beginDate = DateUtil.offsetMonth(new Date(), -1); // 一个月前的日期
        List<Map<String, Object>> result = null;
        String columnName = "";// 立项日期/结项日期的字段名称
        // 根据tab名称判断是查询最近创建还是近期完成
        if (ConvertUtil.convertToString(paraMap.get("tabName")).equals("recentlyCreat")) {
            columnName = "FINISHDATE";
        } else if (ConvertUtil.convertToString(paraMap.get("tabName")).equals("recentlyComplete")) {
            columnName = "ACTUALENDDATE";
        }
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" MpmProject.{2} BETWEEN {0} AND {1} ", SQLAdapter.toDateLong(DateUtil.formatDateTime(beginDate)),
                SQLAdapter.toDateLong(DateUtil.formatDateTime(new Date())), columnName);
        sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(MpmProjectEntity.tableName,
                MpmProjectEntity.FieldProjectcode, ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
        result = this.queryMapForPage(sql.toString(), 1, ConvertUtil.convertToInt(paraMap.get("pageSize")),
                ConvertUtil.convertToString(paraMap.get("sidx")), ConvertUtil.convertToString(paraMap.get("sord")));
        return result;
    }
    /**
     * @author: houyuhang
     * @date: 2021-12-01
     * @description: 获取首页是否有“公司数据”的权限
     * @return: AtomicBoolean
     */
    public AtomicBoolean getIndexPermission(Map<String,Object> paraMap) {
        AtomicBoolean hasOrg = new AtomicBoolean(false);
        // 根据系统参数判断当前登录用户是否有“公司数据”TAB页的权限
        String indexOrgTabPermissionRoles = "," + ParameterCache.getValue("indexOrgTabPermissionRoles") + ",";// 根据角色判断（数据的值为角色编码，多个角色以逗号隔开）
        // 如果当前用户的角色列表中包含任意一个系统参数中配置角色，则有orgTab页的权限
        List<CboRoleEntity> roleList = this.getUserBean().getRoleList();
        for(CboRoleEntity role : roleList) {
            // 排除角色code为空的情况
            if(StringUtil.isEmpty(role.getCode())) {
                continue;
            }
            if(indexOrgTabPermissionRoles.contains("," + role.getCode() + ",")) {
                hasOrg.set(true);
                break;
            }
        }
        return hasOrg;
    }
    /**
     * @description: 首页echarts数据
     * @param: paraMap
     * @return: Map<String,Object>
     * @author houyuhang
     * @date: 2021/12/01
     */
    @Override
    public Map<String,Object> queryProjectLevelSatistics(Map<String,Object> paraMap) {
        Map<String, Object> result = new HashMap<>();
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle("mpmproject.state =9 and projectstate = {0} ",MpmSystemConst.ExecuteStateCode);
        sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(MpmProjectEntity.tableName,
                MpmProjectEntity.FieldProjectcode, ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
        // 按照项目级别统计
        List<Map<String, Object>> listForLevel = this.queryMapByWhere(sql.toString(), "projectLevelStatiStic");
        // 转换为Echarts需要的数据格式
        listForLevel = this.formatMpmEchartsData("MpmProjectLevel",
                "projectlevel", "levelcount", listForLevel);
        // 按照项目状态统计
        List<Map<String, Object>> listForState = this.queryMapByWhere(sql.toString(), "projectStatStatiStic");
        // 转换为Echarts需要的数据格式
        listForState = this.formatMpmEchartsData("MpmProjectAbnormalState",
                "abnormalstate", "statecount", listForState);
        result.put("projectLevelStatisticInfo", listForLevel);
        result.put("projectStateStatisticInfo", listForState);
        return result;
    }
    /**
     * @description: 首页echarts数据格式转化
     * @return: List<Map<String, Object>>
     * @author houyuhang
     * @date: 2021/12/01
     */
    private List<Map<String, Object>> formatMpmEchartsData(String dataName,String dataCode,String dataValue,List<Map<String, Object>> list) {
        for (Map<String, Object> item : list) {
            // 转化为Echarts
            item.put("name", datacodeCache.getValueDynamic(dataName, ConvertUtil.convertToString(item.get(dataCode)), "code", "name"));
            item.put("code", ConvertUtil.convertToString(item.get(dataCode)));
            item.put("value", ConvertUtil.convertToInt(item.get(dataValue)));
            // 删除无用的key
            item.remove(dataCode);
            item.remove(dataValue);
        }
        return list;
    }
    /**
     * @description: 获取数据看板中各个位置的组件信息
     * @param: paraMap
     * @return: List<Map<String,Object>>
     * @author houyuhang
     * @date: 2021/12/01
     */
    @Override
    public List<Map<String,Object>> getComponentsList(Map<String,Object> paraMap) {
        // 无需根据部门修改数据看板显示元素
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" and (MPMDATABOARDCUSTOMIZERECORD.ORGCODE = 'D1') ");
        List<Map<String, Object>> list = mpmDataBoardCustomizeRecordService.queryMapByWhere(sql.toString(), "queryRecordsForIndex");
        return list;
    }
    /**
     * @description: 获取数据中心组件数据(整个系统中的数据统计)
     * @param: paraMap
     * @return: Map<String, Object>
     * @author houyuhang
     * @date: 2021/12/01
     */
    @Override
    public Map<String, Object> getDataCenterInfo(Map<String,Object> paraMap) {
        Map<String, Object> result = new HashMap<>();
        StringBufferProxy sql = new StringBufferProxy();
        // 查询项目个数(只统计立项通过的项目)
        sql.appendSingle("mpmproject.state =9 and {0}", this.spellSqlForDataBoard(paraMap, MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode));
        int count = this.getCount(sql.toString());
        result.put("count", count);
        // 查询项目金额（立项通过的所有立项单据）
        sql.clear();
        sql.appendSingle("mpmproject.state =9 and {0}", spellSqlForDataBoard(paraMap, MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode));
        List<Map<String, Object>> list = this.queryMapByWhere(sql.toString(), "projectMoneyStatiStic");
        result.put("money", list.size() > 0 ? ConvertUtil.convertToDouble(list.get(0).get("sumparticipatemoney")) : 0);
        return result;
    }
    /**
     * @description: 查询各个省区的项目级别数量情况
     * @param: paraMap
     * @return: Map<String, Object>
     * @author houyuhang
     * @date: 2021/12/01
     */
    @Override
    public Map<String, Object> queryProvincesProjectLevelsInfo(Map<String,Object> paraMap) {
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" state = 9 and {0}", spellSqlForDataBoard(paraMap, MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode));
        List<Map<String, Object>> list = this.queryMapByWhere(sql.toString(), "getProjectLevelsCount");
        // 处理为echarts数据格式
        Map<String,Object> result = this.formatEchartsDataForProjectLevel(new ArrayList<>(), new ArrayList<>(),
                new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),list);
        return result;
    }
    /**
     * @description: 处理各个省区的项目级别数量情况为Echarts数据
     * @return: Map<String, Object>
     * @author houyuhang
     * @date: 2021/12/01
     */
    private Map<String,Object> formatEchartsDataForProjectLevel(List<String> categoryList,List<String> ACountList,List<String> BCountList,
                                                 List<String> CCountList,List<String> DCountList,List<Map<String,Object>> list) {
        Map<String, Object> result = new HashMap<>();
        for (Map<String, Object> item : list) {
            String deptname = ConvertUtil.convertToString(item.get("deptname"));
            categoryList.add(deptname.substring(deptname.lastIndexOf("\\") + 1));
            ACountList.add(ConvertUtil.convertToString(item.get("A")));
            BCountList.add(ConvertUtil.convertToString(item.get("B")));
            CCountList.add(ConvertUtil.convertToString(item.get("C")));
            DCountList.add(ConvertUtil.convertToString(item.get("D")));
        }
        result.put("categoryList", categoryList);
        result.put("ACountList", ACountList);
        result.put("BCountList", BCountList);
        result.put("CCountList", CCountList);
        result.put("DCountList", DCountList);
        return result;
    }
    /**
     * @description: 数据看板上项目级别饼图信息
     * @param: paraMap
     * @return: List<Map<String, Object>>
     * @author houyuhang
     * @date: 2021/12/01
     */
    @Override
    public List<Map<String, Object>> getDataBoardProjectLevelEhartInfo(Map<String,Object> paraMap) {
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" mpmproject.state=9 ");
        sql.appendSingle(" and {0} ", this.spellSqlForDataBoard(paraMap, MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode));
        // 按照项目级别统计
        List<Map<String, Object>> listForLevel = this.queryMapByWhere(sql.toString(), "projectLevelStatiStic");
        // 转换为Echarts需要的数据格式
        listForLevel = this.formatMpmEchartsData("MpmProjectLevel",
                "projectlevel", "levelcount", listForLevel);
        return listForLevel;
    }
    /**
     * @description: 查询项目列表
     * @param: paraMap
     * @return: Page
     * @author houyuhang
     * @date: 2021/12/01
     */
    public Page listForMpmIndexController(Map<String,Object> paraMap) {
        Query query = new Query(paraMap);
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" MpmProject.state = 9 and {0}", spellSqlForDataBoard(paraMap,
                MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode));
        String sqlWhere = sql.toString();
        int totalCount = this.getCount(sqlWhere);
        List<Map<String, Object>> tempList = null;
        if (query.getPageSize() > 0) {
                tempList = this.queryMapForPage(sqlWhere, query.getCurrentPage(), query.getPageSize(),
                        query.getSidx(), query.getSord(), "queryMapForPageForIndex");
        } else {
            tempList = this.queryMapByWhere(sqlWhere);
        }
        mpmProjectPolymerizationService.setCurrentMilePost(tempList);
        this.setDispFields(tempList);
        Page page = new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
        return page;
    }
    /**
     * 获取综合项目信息
     * @author: houyuhang
     * @date: 2021-12-01
     * @return ResponseResult<Object>
     */
    public List<Map<String, Object>> overallProjectInfo(Map<String,Object> paraMap) {
        Map<String, Object> result = new HashMap<>();
        // 获取有权限的项目
        List<MpmProjectEntity> projectList = new ArrayList<>();
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(spellSqlForDataBoard(paraMap, MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode));
        List<MpmProjectEntity> mpmProjectEntities = this.queryByWhere(sql.toString());
        //
        Map<String,List<MpmProjectEntity>> mpmProjectMap = mpmProjectEntities.stream().collect(Collectors.groupingBy(item -> item.getProjectstate()));
        // 获取项目状态
        List<Map<String, Object>> projectStateList = datacodeCache.getCodeListMap("MpmProjectState", "", "sortcode");
        // 按状态统计
        List<Map<String, Object>> echartsDataForProjectStateForMobile = new ArrayList<>();
        for (Map<String, Object> stat : projectStateList) {
            String categoryCode = stat.get("code").toString();
            Map<String, Object> resultTemp = new HashMap<>();
            int categoryNum;
            // 项目该状态的项目或者状态值为0（立项中）
            if(mpmProjectMap.get(categoryCode) == null || "0".equals(categoryCode)) {
                categoryNum = 0;
            } else {
                categoryNum = mpmProjectMap.get(categoryCode).size();
            }
            resultTemp.put("name", stat.get("name"));
            resultTemp.put("code", stat.get("code"));
            resultTemp.put("value", categoryNum);
            echartsDataForProjectStateForMobile.add(resultTemp);
        }
        result.put("projectStatDataForMobile", echartsDataForProjectStateForMobile);
        return echartsDataForProjectStateForMobile;
    }
    /**
     * 获取项目信息 sd系统hessian调用接口
     * @author: houyuhang
     * @date: 2022-01-07
     * @return List<Map<String, Object>>
     */
    public List<Map<String, Object>> queryMpmProjectCodeByChanceclue(String whereSql) {
        List<Map<String, Object>> res = this.queryMapByWhere(whereSql,"queryPolymarizationMapByWhere");
        return res;
    }
    /**
     * @description: 获取运营部门，当前存在三级部门，如果查不到所在部门的运营部门，
     * 则查询2所在部门的二级部门，
     * 如果所在二级部门也没有运营部门，则查询所在的一级部门运营部门
     * 不存在一级运营部门，返回null对象，不抛出异常
     * @param:
     * @return: com.topscomm.mis.pojo.MisDeptArchEntity
     * @author Administrator
     * @date: 2021/1/21 13:59
     */
    public MisDeptArchEntity getDeptArchForQuery(String deptCode) {
        String deptCodeThis = "";
        if (!"".equals(deptCode) && deptCode != null) {
            deptCodeThis = deptCode;
        } else {
            deptCodeThis = this.getSessionUserBean().getDept().getCode();
        }
        StringBufferProxy sqlForDeptArch = new StringBufferProxy();
        sqlForDeptArch.appendSingle(" EXISTS (SELECT DEPTARCHCODE FROM MISDEPTARCHRELATED WHERE MISDEPTARCH.CODE = MISDEPTARCHRELATED.DEPTARCHCODE AND MISDEPTARCHRELATED.DEPTCODE = '{0}')", deptCodeThis);
        // 查询所在部门的运营部门
        List<Map<String, Object>> listDeptArchRelate = new ArrayList<>();
        listDeptArchRelate = misDeptArchService.queryMapByWhere(sqlForDeptArch.toString());
        if (listDeptArchRelate.size() == 0) {
            // 如果没有查询到所在运营部门则查询二级部门
            sqlForDeptArch.clear();
            // 所在部门未维护运营部门，查询所在二级部门的运营部门
            // 注意区分分公司
            if (deptCodeThis.contains("_")) {//分公司逻辑
                // 截取“_”后的字符串，如果是分公司则截取_后的六位
                String subDeptCode = deptCodeThis.substring(deptCodeThis.indexOf("_") + 1);
                if (subDeptCode.length() > 6) {
                    String deptCodeFix = deptCodeThis.substring(0, deptCodeThis.indexOf("_") + 1);
                    sqlForDeptArch.appendSingle(" EXISTS (SELECT DEPTARCHCODE FROM MISDEPTARCHRELATED WHERE MISDEPTARCH.CODE = MISDEPTARCHRELATED.DEPTARCHCODE AND MISDEPTARCHRELATED.DEPTCODE = '{0}')", deptCodeFix + subDeptCode.substring(0, 6));
                }
            } else {
                // 如果不是分公司则截取前6位
                if (deptCodeThis.length() > 6) {
                    String subDeptCode = deptCodeThis.substring(0, 6);
                    sqlForDeptArch.clear();
                    sqlForDeptArch.appendSingle(" EXISTS (SELECT DEPTARCHCODE FROM MISDEPTARCHRELATED WHERE MISDEPTARCH.CODE = MISDEPTARCHRELATED.DEPTARCHCODE AND MISDEPTARCHRELATED.DEPTCODE = '{0}')", subDeptCode);
                }
            }
            if (!sqlForDeptArch.toString().equals("")){
                // 查询二级部门的运营部门
                listDeptArchRelate = misDeptArchService.queryMapByWhere(sqlForDeptArch.toString());
            }
            // 如果所在二级部门也没有运营部门则查询所在一级部门的运营部门
            if (listDeptArchRelate.size() == 0) {
                if (deptCodeThis.contains("_")) {//分公司逻辑
                    // 截取“_”后的字符串，如果是分公司则截取_后的四位
                    String subDeptCode = deptCodeThis.substring(deptCodeThis.indexOf("_") + 1);
                    String deptCodeFix = deptCodeThis.substring(0, deptCodeThis.indexOf("_") + 1);
                    sqlForDeptArch.appendSingle(" EXISTS (SELECT DEPTARCHCODE FROM MISDEPTARCHRELATED WHERE MISDEPTARCH.CODE = MISDEPTARCHRELATED.DEPTARCHCODE AND MISDEPTARCHRELATED.DEPTCODE = '{0}')", deptCodeFix + subDeptCode.substring(0, 4));
                } else {
                    // 如果不是分公司则截取前4位
                    String subDeptCode = deptCodeThis.substring(0, 4);
                    sqlForDeptArch.clear();
                    sqlForDeptArch.appendSingle(" EXISTS (SELECT DEPTARCHCODE FROM MISDEPTARCHRELATED WHERE MISDEPTARCH.CODE = MISDEPTARCHRELATED.DEPTARCHCODE AND MISDEPTARCHRELATED.DEPTCODE = '{0}')", subDeptCode);
                }
                //  查询一级部门的运营部门
                listDeptArchRelate = misDeptArchService.queryMapByWhere(sqlForDeptArch.toString());
            }
        }
        MisDeptArchEntity entity = new MisDeptArchEntity();
        if (listDeptArchRelate.size() == 1) {
            entity.convertFromMap(listDeptArchRelate.get(0));
            return entity;
        } else {
            return null;
        }
    }

    /**
     * @author: zhangjunyao
     * @date: 2022-03-26
     * @description: 实时更新项目异常状态
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> updateAbnormalState(String projectCode) {
        Map<String, Object> resultMap = new HashMap<>();
        int currentState = Integer.parseInt(MpmSystemConst.AbnormalStateCode.NormalCode);
        String abnormalReason = "正常";
        // 优先级由低到高覆盖currentState，最后赋值给项目
        // 若任务超期则赋值为任务超期状态
        Boolean isTaskOverDue = mpmProjectTaskService.checkTaskOverDue(projectCode);
        if (isTaskOverDue) {
            currentState = Integer.parseInt(MpmSystemConst.AbnormalStateCode.OverdueTaskCode);
            abnormalReason = "任务超期";
        }
        // 若里程碑及任务超期则赋值为里程碑及任务超期状态
        Boolean isMilepostOverDue = mpmProjectMilepostService.checkMilepostOverDue(projectCode);
        if (isMilepostOverDue) {
            currentState = Integer.parseInt(MpmSystemConst.AbnormalStateCode.OverdueMilepostCode);
            abnormalReason = "里程碑及任务超期";
        }
        Boolean isProjectOverDue = checkProjectOverDue(projectCode);
        if (isProjectOverDue) {
            currentState = Integer.parseInt(MpmSystemConst.AbnormalStateCode.OverdueProjectCode);
            abnormalReason = "项目超期";
        }
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" {0} = '{1}' ", MpmProjectEntity.FieldProjectcode, projectCode);
        MpmProjectEntity mpmProjectEntity = this.queryObjectByWhere(sql.toString());
        mpmProjectEntity.setAbnormalstate(currentState);
        mpmProjectEntity.setAbnormalreason(abnormalReason);
        this.updateEntity(mpmProjectEntity);
        resultMap.put("message", "项目状态更新为“" + abnormalReason + "”");
        return resultMap;
    }

    /**
     * @author: zhangjunyao
     * @date: 2022-03-21
     * @description: 查询项目异常状态
     * @modify:
     */
    private Boolean checkProjectOverDue(String projectCode) {
        Boolean isProjectOverDue = false;
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" {0} = '{1}' ", MpmProjectEntity.FieldProjectcode, projectCode);
        MpmProjectEntity mpmProjectEntity = this.queryObjectByWhere(sql.toString());
        // 转换日期格式，只保留日期部分
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date currentDate, planEndDate;
        try {
            currentDate = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
            planEndDate = simpleDateFormat.parse(simpleDateFormat.format(mpmProjectEntity.getPlanenddate()));
        } catch(ParseException ex) {
            ex.printStackTrace();
            throw new MessageException("日期错误，请填写正确格式的日期！");
        }
        if (!ObjectUtil.isEmpty(mpmProjectEntity)) {
            // 若项目超期则赋值为项目超期状态
            if (currentDate.compareTo(planEndDate) > 0) {
                isProjectOverDue = true;
            }
        }
        return isProjectOverDue;
    }

    /**
     * @author: houyuhang
     * @date: 2022-04-09
     * @description:获取项目名称
     * @modify:
     */
    public String queryProjectName(String serviceName, BasicEntity selectEntity) {
        String projectName = "";
        StringBufferProxy backLogSql = new StringBufferProxy();
        if ("mpmProjectService".equals(serviceName)) {
            if (selectEntity != null) {
                projectName = ConvertUtil.convertToString(selectEntity.getValue("projectname"));
            }
        } else if ("mpmProjectChangeService".equals(serviceName)) {
            backLogSql.clear();
            backLogSql.appendSingle(" projectcode='{0}'", ConvertUtil.convertToString(selectEntity.getValue("projectcode2")));
            List<MpmProjectEntity> mpmProjectEntities = this.queryByWhere(backLogSql.toString());
            if (mpmProjectEntities.size() > 0) {
                projectName = mpmProjectEntities.get(0).getProjectname();
            }
        } else {
            backLogSql.clear();
            backLogSql.appendSingle(" projectcode='{0}'", ConvertUtil.convertToString(selectEntity.getValue("projectcode")));
            List<MpmProjectEntity> mpmProjectEntities = this.queryByWhere(backLogSql.toString());
            if (mpmProjectEntities.size() > 0) {
                projectName = mpmProjectEntities.get(0).getProjectname();
            }
        }
        return projectName;
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-09
     * @description:获取项目级别
     * @modify:
     */
    public String queryProjectLevel(String serviceName, BasicEntity selectEntity) {
        String projectLevel = "";
        StringBufferProxy backLogSql = new StringBufferProxy();
        if ("mpmProjectService".equals(serviceName)) {
            if (selectEntity != null) {
                projectLevel = ConvertUtil.convertToString(selectEntity.getValue("projectlevel"));
            }
        } else if ("mpmProjectChangeService".equals(serviceName)) {
            backLogSql.clear();
            backLogSql.appendSingle(" projectcode='{0}'", ConvertUtil.convertToString(selectEntity.getValue("projectcode2")));
            List<MpmProjectEntity> mpmProjectEntities = this.queryByWhere(backLogSql.toString());
            if (mpmProjectEntities.size() > 0) {
                projectLevel = mpmProjectEntities.get(0).getProjectlevel();
            }
        } else {
            backLogSql.clear();
            backLogSql.appendSingle(" projectcode='{0}'", ConvertUtil.convertToString(selectEntity.getValue("projectcode")));
            List<MpmProjectEntity> mpmProjectEntities = this.queryByWhere(backLogSql.toString());
            if (mpmProjectEntities.size() > 0) {
                projectLevel = mpmProjectEntities.get(0).getProjectlevel();
            }
        }
        return projectLevel;
    }
    /**
     * @author: houyuhang
     * @date: 2022-05-09
     * @description:获取项目级别
     * @modify:
     */
    public void overdueMilepostRemindPM(MpmProjectMilepostEntity overDueProjectMilepostEntity, Map<String, MpmProjectEntity> projectMap, List<Map<String, Object>> appMap, List<Map<String, Object>> sysMap, StringBufferProxy milepostcontent, String[] title, String[] remindContent2) {
        // 插入App消息
        String milepostStr = milepostcontent.toString() + remindContent2[1];
        Map<String, Object> milepostappmap = this.insertMessageApp(projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getProjectmanagercode(),
                title[1], milepostStr, projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getId(), MpmProjectMilepostEntity.tableName,
                0);
        appMap.add(milepostappmap);
        // 插入系统消息
        Map<String, Object> mielpostsysmap = this.insertMessageSys(projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getProjectmanagercode(),
                projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getProjectmanager(), title[1], milepostStr,
                projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getId(), MpmProjectMilepostEntity.tableName);
        sysMap.add(mielpostsysmap);
    }

    /**
     * 获取某省区项目 sd系统hessian调用接口
     * @author: hdy
     * @date: 2022-04-15
     * @return Page
     */
	@Override
	public Page queryMpmProjectByDeptcommonCode(String whereSql,Query query) {
		// TODO Auto-generated method stub
		//sqlWhere, query.getCurrentPage(), query.getPageSize(), query.getSidx(), query.getSord()
		int totalCount = this.getCount(whereSql);
		List<Map<String, Object>> tempList = null;
		if (query.getPageSize() > 0) {
			tempList = this.queryMapForPage(whereSql, query.getCurrentPage(), query.getPageSize(), query.getSidx(), query.getSord());
		} else {
			tempList = this.queryMapByWhere(whereSql);
		}
		Page page = new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
		return page;
	}
    /**
     * 查询评分细则是否即将超期（三天/一天）
     * @author: houyuhang
     * @date: 2022-04-25
     * @return Page
     */
    public void bidScoreSoonOverdue(List<Map<String, Object>> appMap, List<Map<String, Object>> sysMap) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date currentDate = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
        StringBufferProxy sql = new StringBufferProxy();
        // 查询已发布(第一、二次自评)但是评分细则未完成且3天即将超期、明天超期、明天为开标日期的任务(该项目为A级且项目在进行中且采购模式不是其他、电商化采购、服务招标采购、单一来源采购)
        sql.appendSingle(" {0}.enabled = 1 and {0}.state = 9 and {0}.times in (1,2) and {1} not like '%1%' and ({2} = {3} or {4} = {5} or {6} = {7}) and {8} = '{9}' and {10} in ('{11}','{14}') and {12} = '{13}' ", MpmProjectBidScoreEntity.tableName, SQLAdapter.isNull(MpmProjectBidScoreFeedBackEntity.FieldIsfinishbidscore, "0"),
                SQLAdapter.toChar(MpmProjectBidScoreEntity.tableName + "." + MpmProjectBidScoreEntity.FieldPlanenddate + "-1, 'yyyy-mm-dd'"), SQLAdapter.toChar(SQLAdapter.getDate() + ", 'yyyy-mm-dd'"),
                SQLAdapter.toChar(MpmProjectBidScoreEntity.tableName + "." + MpmProjectBidScoreEntity.FieldPlanenddate + "-3, 'yyyy-mm-dd'"), SQLAdapter.toChar(SQLAdapter.getDate() + ", 'yyyy-mm-dd'"),
                SQLAdapter.toChar(MpmProjectSaleEntity.FieldBidenddate + "-1, 'yyyy-mm-dd'"), SQLAdapter.toChar(SQLAdapter.getDate() + ", 'yyyy-mm-dd'"), MpmProjectEntity.FieldProjectlevel, MpmSystemConst.ProjectLevel.A,
                MpmProjectSaleEntity.FieldPurchasepattern, MpmSystemConst.PurchasePattern.chanpinBid, MpmProjectEntity.FieldProjectstate, MpmSystemConst.ProjectState.ExecuteStateCode,
                MpmSystemConst.PurchasePattern.dianshang);
        // 当前时间没有超过开标时间
        sql.appendSingle(" and {0} < {1} ", SQLAdapter.getDate(), MpmProjectSaleEntity.FieldBidenddate);
        List<Map<String, Object>> mpmProjectBidScoreEntities = this.queryMapByWhere(sql.toString(), "bidScoreSoonOverdue");
        // 如果没有评分细则超期记录,直接return,不发送消息
        if (CollectionUtil.isEmpty(mpmProjectBidScoreEntities)) {
            return;
        }
        // 发送APP和系统消息
        for(Map<String, Object> mpmProjectBidScoreEntity : mpmProjectBidScoreEntities) {
            Date planEndDate = ConvertUtil.convertToDate(mpmProjectBidScoreEntity.get("planenddate"));
            String times = ConvertUtil.convertToString(mpmProjectBidScoreEntity.get("times"));
            String taskResponsibleCode = ConvertUtil.convertToString(mpmProjectBidScoreEntity.get("responsiblecode"));
            String taskResponsible = ConvertUtil.convertToString(mpmProjectBidScoreEntity.get("responsible"));
            String projectLevel = datacodeCache.getValueDynamic("MpmProjectLevel", ConvertUtil.convertToString(mpmProjectBidScoreEntity.get("projectlevel")), "code", "name");
            String projectName = ConvertUtil.convertToString(mpmProjectBidScoreEntity.get("projectname"));
            String taskName = ConvertUtil.convertToString(mpmProjectBidScoreEntity.get("scoringitem"));
            String[] remindContent = {"三天后到期", "明天到期", "明天为开标日期"};
            String taskTemp = "";
            long mpmId = ConvertUtil.convertToLong(mpmProjectBidScoreEntity.get("mpmid"));
            // 若三天后超期则如下配置消息内容
            if (planEndDate.getTime() - currentDate.getTime() == DAY_MILLSECONDS) {
                taskTemp = remindContent[0];
            } else if (planEndDate.getTime() - currentDate.getTime() == DAY1_MILLSECONDS){
                taskTemp = remindContent[1];
            } else {
                taskTemp = remindContent[2];
            }
            String sourcetype = MpmSystemConst.ProjectScoreCode.first;
            if(times.equals(MpmSystemConst.BidScoreType.secondType)){
                sourcetype = MpmSystemConst.ProjectScoreCode.second;
            }
            //times
            StringBufferProxy taskcontent = new StringBufferProxy();
            taskcontent.appendSingle("【{0}级项目：{1}】“评分细则”任务：“{2}”，{3}，请及时登录系统处理；若责任人未在计划完成日期前完成填写，视为任务超期！",
                    projectLevel, projectName, taskName, taskTemp);
            // 插入App消息
            Map<String, Object> taskappmap = this.insertMessageApp(taskResponsibleCode, "销售项目评分细则任务超期预警", taskcontent.toString(),
                    mpmId, sourcetype, 0);
            appMap.add(taskappmap);
            // 插入系统消息
            Map<String, Object> tasksysmap = this.insertMessageSys(taskResponsibleCode, taskResponsible, "销售项目评分细则任务超期预警", taskcontent.toString(),
                    mpmId, sourcetype);
            sysMap.add(tasksysmap);
        }
    }

    public List<MpmProjectEntity> getMpmProjectByTask(String projectCode) {
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendLineSingle(" {0} = '{1}'", MpmProjectEntity.FieldProjectcode, projectCode);
        return this.queryByWhere(sql.toString());
    }
    /**
     * @Description:    获取项目的省总、sponsor、owner、项目经理人员列表
     * @Author:         mengmeng
     * @Date:           2022/5/10 16:01
     * @Version:        1.0
     */
    public List<String> getProjectUserList(MpmProjectEntity project) {
        List<String> userCode = new ArrayList<>();
        userCode.add(project.getSponsorcode());
        userCode.add(project.getOwnercode());
        userCode.add(project.getProjectmanagercode());
        MisDeptHeaderEntity misDeptHeaderEntity = queryCEO(project.getDeptcode());
        userCode.add(misDeptHeaderEntity.getUsercode());
        return userCode;
    }
    public MisDeptHeaderEntity queryCEO(String deptCode) {
        StringBufferProxy sql = new StringBufferProxy();
        if (deptCode.contains("_")) {
            sql.appendSingle("deptcode ='{0}' and category = 'CEO'", deptCode.substring(0, deptCode.indexOf('_') + 5));
            return misDeptHeaderService.queryByWhere(sql.toString()).get(0);
        } else {
            sql.appendSingle("deptcode ='{0}' and category = 'CEO'", deptCode.substring(0, 4));
            return misDeptHeaderService.queryByWhere(sql.toString()).get(0);
        }
    }
    public void sendFocusMessage(Map<String,Object> paraMap1) {
        // 取消关注，不发送信息
        if (MpmSystemConst.MarkType.OffMark.equals(ConvertUtil.convertToString(paraMap1.get("type")))) {
            return;
        }
        //MpmCommentsEntity comment = (MpmCommentsEntity) entity;
        String sourceType = ConvertUtil.convertToString(paraMap1.get("sourcetype"));
        String sourceId = ConvertUtil.convertToString(paraMap1.get("sourceid"));
        boolean taskFlag = sourceType.equals(MpmProjectTaskEntity.tableName);
        if (taskFlag) {
            // 任务 要给对应的省总、sponsor、owner、项目经理、里程碑及任务责任人、任务责任人
            MpmProjectTaskEntity projectTaskEntity = mpmProjectTaskService.queryById(sourceId);
            List<MpmProjectEntity> mpmProjectList = getMpmProjectByTask(projectTaskEntity.getProjectcode());
            if (CollectionUtils.isEmpty(mpmProjectList)) {
                throw new ServiceException("未查询到该任务所处项目！");
            }
            // 任务责任人
            List<String> userCode = getProjectUserList(mpmProjectList.get(0));
            userCode.add(projectTaskEntity.getResponsiblecode());
            // 里程碑及任务责任人
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendLineSingle(" {0} = '{1}' and  {2} = {3}", MpmProjectMilepostEntity.FieldOperatecode, projectTaskEntity.getMilepostcode(), MpmProjectMilepostEntity.FieldEnabled, 1);
            List<MpmProjectMilepostEntity> projectMilepostEntityList = mpmProjectMilepostService.queryByWhere(sql.toString());
            if (!CollectionUtils.isEmpty(projectMilepostEntityList)) {
                userCode.add(projectMilepostEntityList.get(0).getResponsiblecode());
            }
            List<CboUserEntity> userList = cboUserService.queryByWhere(" code in (" + userCode.stream().map(item -> "'" + item + "'").collect(Collectors.joining(",")) + ")");
            sql.clear();
            String projectName = projectTaskEntity.getProjectname();
            projectName = projectName.endsWith("项目") ? projectName : (projectName + "项目");
            String taskName = projectTaskEntity.getTaskname();
            taskName = taskName.endsWith("任务") ? taskName : (taskName + "任务");
            sql.appendLineSingle("您负责的{0}{3}已被{1}[{2}]关注，请登录销售项目系统查阅。", projectName, getSessionUserBean().getUser().getName(), getSessionUserBean().getUser().getCode(), taskName);

            // 发送消息
            insertMessageAppFromTask(userList, sql.toString(), ConvertUtil.convertToLong(sourceId));


        }
        else {
            // 项目需要给省总、sponsor、owner、项目经理发送消息提醒
            MpmProjectEntity project = this.queryById(sourceId);
            List<String> userCode = getProjectUserList(project);

            List<CboUserEntity> userList = cboUserService.queryByWhere(" code in (" + userCode.stream().map(item -> "'" + item + "'").collect(Collectors.joining(",")) + ")");
            StringBufferProxy sql = new StringBufferProxy();
            String projectName = project.getProjectname();
            projectName = projectName.endsWith("项目") ? projectName : (projectName + "项目");
            StringBufferProxy sqlContent = new StringBufferProxy();
            sqlContent.appendLineSingle("您负责的{0}已被{1}[{2}]关注，请登录销售项目系统查阅。", projectName, getSessionUserBean().getUser().getName(), getSessionUserBean().getUser().getCode());
            // 设置权限
            Map<String, Object> paraMap = new HashMap<>();
            paraMap.put("projectcode", project.getProjectcode());
            List<Map<String, Object>> mpmProjectTaskList = mpmProjectTaskService.queryTaskForSystem(paraMap);
            List<String> permissionUserCodeList = new ArrayList<>(userCode);
            if (!CollectionUtils.isEmpty(mpmProjectTaskList)) {
                permissionUserCodeList.addAll(mpmProjectTaskList.stream().map(map -> ConvertUtil.convertToString(map.get(MpmProjectTaskEntity.FieldResponsiblecode))).collect(Collectors.toList()));
                // 查询里程碑及任务责任人
                sql.clear();
                sql.appendLineSingle(" {0} in ({1}) and  {2} = {3}", MpmProjectMilepostEntity.FieldOperatecode, mpmProjectTaskList.stream().map(item -> "'" +  ConvertUtil.convertToString(item.get(MpmProjectTaskEntity.FieldMilepostcode)) + "'").collect(Collectors.joining(",")), MpmProjectMilepostEntity.FieldEnabled, 1);
                List<MpmProjectMilepostEntity> projectMilepostEntityList = mpmProjectMilepostService.queryByWhere(sql.toString());
                if (!CollectionUtils.isEmpty(projectMilepostEntityList)) {
                    permissionUserCodeList.addAll(projectMilepostEntityList.stream().map(MpmProjectMilepostEntity::getResponsiblecode).collect(Collectors.toList()));
                }
            }
            // 发送消息
            insertMessageAppFromTask(userList, sqlContent.toString(), ConvertUtil.convertToLong(sourceId));
        }
    }
    private void insertMessageAppFromTask(List<CboUserEntity> userList, String content, long id) {
        if (CollectionUtils.isEmpty(userList)) {
            return;
        }
        List<Map<String, Object>> cboMessageAppMapList = new ArrayList<>();
        List<BasicEntity> cboMessageSysEntityList = new ArrayList<>();
        for (CboUserEntity user : userList) {
            // MessageApp消息发送
            Map<String, Object> cboMessageAppMap = new HashMap<>();
            cboMessageAppMap.put(CboMessageAppEntity.FieldContent, content);
            cboMessageAppMap.put(CboMessageAppEntity.FieldSourcetype, MpmCommentsEntity.tableName);
            cboMessageAppMap.put(CboMessageAppEntity.FieldSourceid, id);
            cboMessageAppMap.put(CboMessageAppEntity.FieldReceiverid, user.getId());
            cboMessageAppMap.put("usercode", user.getCode());
            cboMessageAppMap.put(CboMessageAppEntity.FieldSendtype, 0);
            //            cboMessageAppMap.put(CboMessageAppEntity.FieldExtendfield1, projectName + subjectStr);// 从task表改
            cboMessageAppMapList.add(cboMessageAppMap);
            // MessageSys消息发送
            CboMessageSysEntity cboMessageSysEntity = new CboMessageSysEntity();
            cboMessageSysEntity.setContent(content);
            cboMessageSysEntity.setSourcetype(MpmCommentsEntity.tableName);
            cboMessageSysEntity.setSourceid(id);
            cboMessageSysEntity.setReceivercode(user.getCode());
            cboMessageSysEntity.setReceivername(user.getName());
            cboMessageSysEntity.setSubject("销售项目关注提醒");
            cboMessageSysEntityList.add(cboMessageSysEntity);
        }
        // 每50条数据插一次，防止oa hessian超时
        int baseRemindTaskEntityAppRemindListSize = userList.size();
        int lastIndex = 0;
        for (int i = 1; i <= baseRemindTaskEntityAppRemindListSize; i++) {
            if (i % 50 == 0 || i == (baseRemindTaskEntityAppRemindListSize)) {
                try {
                    this.cboMessageAppService.insertList(cboMessageAppMapList.subList(lastIndex, i));
                    this.cboMessageSysService.insertBatch(cboMessageSysEntityList.subList(lastIndex, i));
                } catch (Exception e) {
                }
                lastIndex = i;
            }
        }
    }
    /**
     * 查询评分细则是否即将超期（三天/一天）
     * @author: houyuhang
     * @date: 2022-07-25
     * @return Page
     */
    public void sendSecondBidScoreAlert(List<Map<String, Object>> appMap, List<Map<String, Object>> sysMap) throws ParseException {
        String nowStr = DateUtil.format(new Date(), "yyyy-MM-dd");
        StringBufferProxy sql = new StringBufferProxy();
        // 查询省招A级，进行中项目，当前日期为挂网日期后一天
        sql.appendSingle(" projectlevel = '{0}' and (({1} = '{2}' and projectstate = '{5}') or ({1} = '{4}' and (EXISTBIDSCORE = '1' or (EXISTBIDSCORE = '0' and existbidscorestate not in ('1','9'))))) and clientlevel like '%{3}%' ",
                MpmSystemConst.ProjectLevel.A, MpmProjectSaleEntity.FieldPurchasepattern, MpmSystemConst.PurchasePattern.chanpinBid,
                MpmSystemConst.ClientLevel.Province, MpmSystemConst.PurchasePattern.dianshang,MpmSystemConst.ProjectState.ExecuteStateCode);
        sql.appendSingle(" and {0} + 1 = {1} ", MpmProjectSaleEntity.FieldBidbegindate, SQLAdapter.toDateShort(nowStr));
        List<Map<String, Object>> mpmProjectEntities = this.queryMapByWhere(sql.toString(), "sendSecondBidScoreAlert");
        // 如果没有评分细则超期记录,直接return,不发送消息
        if (CollectionUtil.isEmpty(mpmProjectEntities)) {
            return;
        }
        // 发送APP和系统消息
        for(Map<String, Object> mpmProjectEntity : mpmProjectEntities) {
            String projectManagerCode = ConvertUtil.convertToString(mpmProjectEntity.get("projectmanagercode"));
            String projectManager = ConvertUtil.convertToString(mpmProjectEntity.get("projectmanager"));
            String projectname = ConvertUtil.convertToString(mpmProjectEntity.get("projectname"));
            String bidbegindate = DateUtil.format(ConvertUtil.convertToDate(mpmProjectEntity.get("bidbegindate")), "yyyy-MM-dd");
            long id = ConvertUtil.convertToLong(mpmProjectEntity.get("id"));
            StringBufferProxy taskcontent = new StringBufferProxy();
            taskcontent.appendSingle("【A级项目：{0}】于{1}挂网，请尽快组织相关方完成评分细则第二次自评。", projectname, bidbegindate);
            // 插入App消息
            Map<String, Object> taskappmap = this.insertMessageApp(projectManagerCode, "第二次自评提醒", taskcontent.toString(),
                    id, PROJECTSOURCETYPE, 0);
            appMap.add(taskappmap);
            // 插入系统消息
            Map<String, Object> tasksysmap = this.insertMessageSys(projectManagerCode, projectManager, "第二次自评提醒", taskcontent.toString(),
                    id, PROJECTSOURCETYPE);
            sysMap.add(tasksysmap);
        }
    }

    /***
     * @description: 置顶与取消置顶功能
     * @param paraMap
     * @return
     * @author: jiangtao1
     * @date: 2022/8/10 10:08
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String changeTop(Map<String, Object> paraMap) {
        String projectcode = paraMap.get("projectcode").toString();
        String type = ConvertUtil.convertToString(paraMap.get("type"));
        String sourcetype = ConvertUtil.convertToString(paraMap.get("sourcetype"));
        String message = "";
        StringBufferProxy sql = new StringBufferProxy();
        if(MpmProjectEntity.tableName.equals(sourcetype) || MpmProjectPlanEntity.tableName.equals(sourcetype) || MpmProjectReviewEntity.tableName.equals(sourcetype)) {
            if("0".equals(type)) {
                sql.appendSingle("update {0} set whethertop = '1', toptime = sysdate where projectcode = '{1}' and enabled = 1",sourcetype,projectcode);
                message = "置顶成功！";
            } else {
                sql.appendSingle("update {0} set whethertop = '0', toptime = null where projectcode = '{1}' and enabled = 1",sourcetype,projectcode);
                message = "取消置顶成功！";
            }
            this.updateExecute(sql.toString());
        } else {
            message = "操作成功！";
        }
        return message;
    }

    /***
     * @description: 项目编号增加春季、秋季攻势前缀(春季 1;秋季 2; 无 null)
     * @return
     * @author: houyuhang
     * @date: 2022/10/12
     * @modify:
     */
    @Transactional
    public void addProjectAttackFirst(String projectcode, String param) {
        StringBufferProxy sql = new StringBufferProxy();
        String[] split = MpmSystemConst.AttackTableName.split(",");
        projectcode = "'" + projectcode.replaceAll(",", "','") + "'";
        String extraStr = StringUtil.isEmpty(param) ? "" : MpmSystemConst.ProjectAttack.Spring.equals(param) ? " 'CJ-' || " : " 'QJ-' || ";
        String atttckStr = StringUtil.isEmpty(param) ? "" : MpmSystemConst.ProjectAttack.Spring.equals(param) ? "1" : "2";
        // 更新主表projectattack的值
        sql.clear();
        sql.appendSingle(" update mpmproject set projectattack = '{0}' where projectcode in ({1}) ", atttckStr, projectcode);
        this.updateExecute(sql.toString());
        for (String tablename : split) {
            if ("MPMPROJECTCHANGE".equals(tablename)) {
                sql.clear();
                sql.appendSingle("update {0} set projectcode2 = {1} substr(projectcode2, -12) where projectcode2 in ({2}) ", tablename, extraStr, projectcode);
                this.updateExecute(sql.toString());
            } else {
                sql.clear();
                sql.appendSingle("update {0} set projectcode = {1} substr(projectcode, -12) where projectcode in ({2}) ", tablename, extraStr, projectcode);
                this.updateExecute(sql.toString());
            }
        }
        // 更新sd项目关联销售项目编号值
        sql.clear();
        sql.appendSingle(" update sdproject set mpmprojectcode = {0} substr(mpmprojectcode, -12) where mpmprojectcode is not null and mpmprojectcode in ({1}) and mpmprojectcode NOT LIKE '%,%' ", extraStr, projectcode);
        this.updateExecute(sql.toString());
        // 更新机会点项目编号值
        sql.clear();
        sql.appendSingle(" update ltcchancebackbone set leadofmpmprojectcode = {0} substr(leadofmpmprojectcode, -12) where leadofmpmprojectcode is not null and leadofmpmprojectcode in ({1}) and leadofmpmprojectcode NOT LIKE '%,%' ", extraStr, projectcode);
        this.updateExecute(sql.toString());
        // 更新投标项目编号值
        sql.clear();
        sql.appendSingle(" update ltc_bid_apply set mpmprojectcode = {0} substr(mpmprojectcode, -12) where mpmprojectcode is not null and mpmprojectcode in ({1}) and mpmprojectcode NOT LIKE '%,%' ", extraStr, projectcode);
        this.updateExecute(sql.toString());
    }
    /**
     * @author: houyuhang
     * @date: 2022/11/15
     * @description: 审批后修改风险状态
     * @modify:
     */
    @Override
    protected void afterApprove(TapEntity billEntity, CboApprovalNodeInsEntity nodeIns, CboApprovalNodeEntity node,
                                SessionUserBean sessionUserBean) {
        MpmProjectEntity mpmProjectEntity = (MpmProjectEntity) billEntity;
        if(mpmProjectEntity.getState() == 9) {
            // 修改项目关联风险，状态置为审批结束
            mpmProjectRiskService.finishRiskFlow(mpmProjectEntity);
        }
        super.afterApprove(billEntity, nodeIns, node, sessionUserBean);
    }
    public Map<String, Object> getMeetOfSingleProjectInAGivenTime(Date start, Date end, String sourceid, List<Map<String, Object>> meetList) {
        // 开始时间（当前周周一）
        Calendar startDate = Calendar.getInstance();
        startDate.setTime(start);
        // 结束时间（当前周周日）
        Calendar endDate = Calendar.getInstance();
        endDate.setTime(end);
        // 获取meetlist中这个项目的信息
        List<Map<String, Object>> meetings = meetList.stream().filter(m -> sourceid.contentEquals(ConvertUtil.convertToString(m.get("sourceid")))).collect(Collectors.toList());
        int count = 0;
        int countforActual = 0;
        while (startDate.before(endDate)) {
            // 本周需要开周会且本周周会已开，count为实际开会次数
            if (this.needWeekMeet(startDate) && this.getMeetingsForWeek(startDate, meetings)) {
                 int meetCount = 0;
                 meetCount = this.getMeetingNumForWeek(startDate, meetings);
                 count++;
                 countforActual += meetCount;
            }
            startDate.add(Calendar.WEEK_OF_YEAR, 1);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("meetactual", countforActual);
        result.put("meetactualforactual", count);
        return result;
    }

    private boolean getMeetingsForWeek(Calendar weekStart, List<Map<String, Object>> meetings) {
        // 会议类型为项目周会且已上传会议纪要
        Calendar weekEnd = Calendar.getInstance();
        weekEnd.setTime(weekStart.getTime());
        weekEnd.add(Calendar.DATE, 7);
        int nums = (int) meetings.stream().filter(meet -> MpmSystemConst.MpmMeetType.WEEKMEET.equals(ConvertUtil.convertToString(meet.get("dispmeettypeid"))))
                .filter(meet -> ConvertUtil.convertToBoolean(meet.get("recorduploaded"))).filter(meet -> {
            Date start = ConvertUtil.convertToDate(meet.get("begintime"));
            return start.after(weekStart.getTime()) && start.before(weekEnd.getTime());
        }).count();
        return nums > 0;
    }

    // 获取实际每周开会次数
    private int getMeetingNumForWeek(Calendar weekStart, List<Map<String, Object>> meetings) {
        // 会议类型为项目周会且已上传会议纪要
        Calendar weekEnd = Calendar.getInstance();
        weekEnd.setTime(weekStart.getTime());
        weekEnd.add(Calendar.DATE, 7);
        int nums = (int) meetings.stream().filter(meet -> MpmSystemConst.MpmMeetType.WEEKMEET.equals(ConvertUtil.convertToString(meet.get("dispmeettypeid"))))
                .filter(meet -> ConvertUtil.convertToBoolean(meet.get("recorduploaded"))).filter(meet -> {
                    Date start = ConvertUtil.convertToDate(meet.get("begintime"));
                    return start.after(weekStart.getTime()) && start.before(weekEnd.getTime());
                }).count();
        return nums;
    }


    /***
     * @description: 获取实开周会信息
     * @return
     * @author: houyuhang
     * @date: 2022/12/15
     * @modify:
     */
    public List<Map<String, Object>> queryMeetPerWeek(String token, List<Map<String,Object>> projectList) {
        // 从会议系统获取项目对应的会议信息
        String qry_sourceids = projectList.stream().map(m->ConvertUtil.convertToString(m.get("id"))).collect(Collectors.joining(","));
        String qry_sorucetype = MpmSystemConst.MpmMeetParam.SOURCETYPE;
        String qry_soruceapp = MpmSystemConst.MpmMeetParam.SOURCEAPP;
        String qry_state = MpmSystemConst.MpmMeetParam.STATE;
        JSONObject paramap = new JSONObject();
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCETYPE,qry_sorucetype);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCEAPP,qry_soruceapp);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCEIDS,qry_sourceids);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_STATE,qry_state);
        String url  = Config.getInstance().getValue("MeetServerUrl", "")+"/meet/meetManage/list";
        String result = HttpRequest.post(url).auth(token).body(paramap.toJSONString()).execute().body();
        Map jsonRes = JSONObject.parseObject(result, Map.class);
        Map<String, Object> resultMap = (Map) jsonRes.get("result");
        List<Map<String, Object>> meetList = (List) resultMap.get("dataList");
        // 遍历项目，得到实开周会信息,复盘会召开日期
        List<Map<String, Object>> meetActual = new ArrayList<>();
        for (Map<String,Object> projectMap : projectList) {
            Map<String, Object> tempMap = new HashMap<>();
            tempMap.put("id", ConvertUtil.convertToString(projectMap.get("id")));
            if (!ObjectUtil.isEmpty(projectMap.get("meetbegindate"))) {
                tempMap.putAll(this.getMeetOfSingleProjectInAGivenTime(ConvertUtil.convertToDate(projectMap.get("meetbegindate")), getMeetPreviousDate(ConvertUtil.convertToDate(projectMap.get("meetenddate"))), ConvertUtil.convertToString(projectMap.get("id")), meetList));
            }
            Date reviewMeetDate = this.getReviewMeetDate(ConvertUtil.convertToString(projectMap.get("id")), meetList);
            tempMap.put("reviewmeet", reviewMeetDate);
            meetActual.add(tempMap);
        }
        return meetActual;
    }
    /***
     * @description: 判断本周是否需要开周会
     * @return
     * @author: houyuhang
     * @date: 2022/12/15
     * @modify:
     */
    public boolean needWeekMeet(Calendar startDate) {
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" enabled = 1 ");
        List<MpmProjectNoMeetWeekEntity> weekEntities = mpmProjectNoMeetWeekService.queryByWhere(sql.toString());
        for (MpmProjectNoMeetWeekEntity weekEntity : weekEntities) {
            if (weekEntity.getMeetbegindate().compareTo(startDate.getTime()) == 0) {
                return false;
            }
        }
        return true;
    }
    /***
     * @description: 获取复盘会议日期
     * @return
     * @author: houyuhang
     * @date: 2022/12/15
     * @modify:
     */
    public Date getReviewMeetDate(String sourceid, List<Map<String, Object>> meetList) {
        List<Map<String, Object>> tempMeetList = meetList.stream().filter(m -> sourceid.equals(ConvertUtil.convertToString(m.get("sourceid")))).filter(item -> MpmSystemConst.MpmMeetType.REVIEWMEET.equals(ConvertUtil.convertToString(item.get("dispmeettypeid")))).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(tempMeetList)) {
            return null;
        } else {
            return ConvertUtil.convertToDate(tempMeetList.get(0).get("begintime"));
        }
    }
    /***
     * @description: 判断该项目的项目经理是否为省总
     * @return
     * @author: houyuhang
     * @date: 2023/02/03
     * @modify:
     */
    public boolean queryIsProvinceManager(String projectManagerCode) {
        return mmsDeptExtraInfoService.getAsPMDeptCommonCodeByUserCode(projectManagerCode).size() > 0;
    }
    /***
     * @description: 获取项目的所有会议信息
     * @return
     * @author: houyuhang
     * @date: 2023/03/01
     * @modify:
     */
    public List<Map<String, Object>> queryMeetListInfo(String token, String id) {
        // 从会议系统获取项目对应的会议信息
        String qry_sorucetype = MpmSystemConst.MpmMeetParam.SOURCETYPE;
        String qry_soruceapp = MpmSystemConst.MpmMeetParam.SOURCEAPP;
        String qry_state = MpmSystemConst.MpmMeetParam.STATE;
        JSONObject paramap = new JSONObject();
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCETYPE,qry_sorucetype);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCEAPP,qry_soruceapp);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCEIDS, id);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_STATE,qry_state);
        String url  = Config.getInstance().getValue("MeetServerUrl", "")+"/meet/meetManage/list";
        String result = HttpRequest.post(url).auth(token).body(paramap.toJSONString()).execute().body();
        Map jsonRes = JSONObject.parseObject(result, Map.class);
        Map<String, Object> resultMap = (Map) jsonRes.get("result");
        List<Map<String, Object>> meetList = (List) resultMap.get("dataList");
        return meetList;
    }
    /***
     * @description: 获取复盘会并已上传会议纪要
     * @return
     * @author: houyuhang
     * @date: 2023/03/01
     * @modify:
     */
    public boolean queryReviewMeetInfo(String token, Map<String,Object> paraMap) {
        String projectcode = ConvertUtil.convertToString(paraMap.get("qry_projectcode"));
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" projectcode = '{0}' ", projectcode);
        MpmProjectEntity mpmProjectEntity = this.queryObjectByWhere(sql.toString());
        if (ObjectUtil.isEmpty(mpmProjectEntity)) {
            return false;
        }
        List<Map<String, Object>> meetInfo = this.queryMeetListInfo(token, ConvertUtil.convertToString(mpmProjectEntity.getId()));
        List<Map<String, Object>> filterInfo = meetInfo.stream().filter(item -> MpmSystemConst.MpmMeetType.REVIEWMEET.equals(ConvertUtil.convertToString(item.get("dispmeettypeid"))) && (ConvertUtil.convertToBoolean(item.get("audiouploaded")) || ConvertUtil.convertToBoolean(item.get("recorduploaded")))).collect(Collectors.toList());
        return filterInfo.size() > 0;
    }
    /***
     * @description: 获取会议信息
     * @return
     * @author: houyuhang
     * @date: 2023/03/02
     * @modify:
     */
    public List<Map<String, Object>> queryMeetStatInfo(String token, Map<String, Object> paraMap) {
        // 按部门或项目经理维度导出
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(" enabled = 1 and state = 9 ");
        if (!ObjectUtil.isEmpty(paraMap.get("startdate")) && !ObjectUtil.isEmpty(paraMap.get("enddate"))) {
            String startdateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("startdate")) + " 00:00:00");
            String enddateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("enddate")) + " 23:59:59");
            // 1或2 1、计划开始时间小于等于选定的结束时间且实际（没有选择计划）完成时间大于等于选定的开始时间 2、计划结束时间小于选定的开始时间且项目处于进行中状态
            whereSql.appendSingle(" and ({0} <= {1} and {2} >= {3} or {4} < {5} and {6} = {7}) ", MpmProjectEntity.FieldPlanstartdate, enddateSql,
                    SQLAdapter.isNull(MpmProjectEntity.FieldActualenddate, MpmProjectEntity.FieldPlanenddate), startdateSql,
                    MpmProjectEntity.FieldPlanenddate, startdateSql, MpmProjectEntity.FieldProjectstate, MpmSystemConst.ProjectState.ExecuteStateCode);
        }
        if (paraMap.containsKey("qry_deptcommoncode")) {
            String value = paraMap.get("qry_deptcommoncode").toString();
            if (!StringUtil.isEmpty(value))
                whereSql.appendSingle(" and mpmproject.deptcommoncode in ({0}) ", value);
        }
        // 采购模式筛选条件
        if (paraMap.containsKey("qry_purchasepattern")) {
            String value = ConvertUtil.convertToString(paraMap.get("qry_purchasepattern"));
            if (!StringUtil.isEmpty(value)) {
                whereSql.appendSingle(" and exists (select 1 from mpmprojectsale where mpmproject.id = mpmprojectsale.id and purchasepattern in ({0})) ", value);
            }
        }else {
            // 默认选择所有采购模式
            whereSql.appendSingle(" and exists (select 1 from mpmprojectsale where mpmproject.id = mpmprojectsale.id and purchasepattern in (" +
                    MpmSystemConst.PurchasePattern.chanpinBid +","+
                    MpmSystemConst.PurchasePattern.fuwuBid +","+
                    MpmSystemConst.PurchasePattern.dianshang +","+
                    MpmSystemConst.PurchasePattern.noBid +","+
                    MpmSystemConst.PurchasePattern.otherNoBid
                    +")) ");
        }
        String userFlag = ConvertUtil.convertToString(paraMap.get("userflag"));
        List<Map<String, Object>> meetInfo = new ArrayList<>();
        if ("dept".equals(userFlag)) {
            meetInfo = this.queryMapByWhere(whereSql.toString(), "queryMeetDept");
        } else {
            meetInfo = this.queryMapByWhere(whereSql.toString(), "queryMeetManager");
        }
        if (CollectionUtil.isEmpty(meetInfo)) {
            return meetInfo;
        }
        // 根据id获取项目信息、会议信息
        String allId = meetInfo.stream().map(item -> ConvertUtil.convertToString(item.get("listid"))).collect(Collectors.joining(","));
        List<MpmProjectEntity> mpmProjectEntities = this.queryByIds(allId);
        Map<String, MpmProjectEntity> mpmProjectEntityMap = mpmProjectEntities.stream().collect(Collectors.toMap(item -> ConvertUtil.convertToString(item.getId()), item -> item, (v1, v2) -> v1));
        List<Map<String, Object>> meetList = this.queryMeetInfoGeneral(token, allId);
        // 获取应开周会、实开周会数量
        for (Map<String, Object> meetMap : meetInfo) {
            int meetNeedCount = 0, meetActualCount = 0, meetActualForCountWeek = 0;
            String listid = ConvertUtil.convertToString(meetMap.get("listid"));
            String[] listidArr = listid.split(",");
            for (String id : listidArr) {
                MpmProjectEntity mpmProjectEntity = mpmProjectEntityMap.get(id);
                if (ObjectUtil.isEmpty(mpmProjectEntity)) {
                    continue;
                }
                Date meetbegindate = mpmProjectEntity.getMeetbegindate();
                Date meetenddate = getMeetPreviousDate(mpmProjectEntity.getMeetenddate());
                Date startdate = ConvertUtil.convertToDate(paraMap.get("startdate"));
                Date enddate = ConvertUtil.convertToDate(paraMap.get("enddate"));
                if (meetbegindate != null) {
                    Date newBeginDate = startdate == null ? meetbegindate : startdate.compareTo(meetbegindate) > 0 ? startdate : meetbegindate;
                    Date newEndDate = enddate == null ? meetenddate : enddate.compareTo(meetenddate) > 0 ? meetenddate : enddate;
                    meetNeedCount += this.setMeetNeedForStat(id, newBeginDate, newEndDate);
                    meetActualCount += this.setMeetActualForStat(newBeginDate, newEndDate, id, meetList);
                    meetActualForCountWeek += this.setMeetActualForStatCount(newBeginDate, newEndDate, id, meetList);
                }
            }
            meetMap.put("meetneed", meetNeedCount);
            meetMap.put("meetactual", meetActualCount);
            meetMap.put("meetactualforcount", meetActualForCountWeek);
        }
        // 计算召开率，未开周数，合计行
        this.getMoreMeetStatDetails(meetInfo);
        this.setDispFields(meetInfo);
        this.calculateMeetTotal(meetInfo);
        this.calculateMeetAverage(meetInfo);
        return meetInfo;
    }
    /***
     * @description: 获取应开周会信息
     * @return
     * @author: houyuhang
     * @date: 2023/03/03
     * @modify:
     */
    public int setMeetNeedForStat(String id, Date begindate, Date enddate) {
        if (begindate == null || enddate == null) {
            return 0;
        }
        if (enddate.compareTo(begindate) < 0) {
            return 0;
        }
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" enabled = 1 ");
        List<MpmProjectNoMeetWeekEntity> mpmProjectNoMeetWeekEntities = mpmProjectNoMeetWeekService.queryByWhere(sql.toString());
        int count = 0;
        for (MpmProjectNoMeetWeekEntity weekEntity : mpmProjectNoMeetWeekEntities) {
            if (weekEntity.getMeetweekdate().compareTo(begindate) >= 0 && weekEntity.getMeetweekdate().compareTo(enddate) <= 0) {
                count++;
            }
        }
        return (int) ((enddate.getTime() - begindate.getTime()) / (7 * 24 * 60 * 60 * 1000L) - count + 1);
    }
    /***
     * @description: 获取实开周会信息
     * @return
     * @author: houyuhang
     * @date: 2023/03/03
     * @modify:
     */
    public int setMeetActualForStat(Date start, Date end, String sourceid, List<Map<String, Object>> meetList) {
        // 开始时间（当前周周一）、结束时间（当前周周日）
        Calendar startDate = Calendar.getInstance();
        startDate.setTime(start);
        Calendar endDate = Calendar.getInstance();
        endDate.setTime(end);
        // 获取meetlist中这个项目的信息
        List<Map<String, Object>> meetings = meetList.stream().filter(m -> sourceid.contentEquals(ConvertUtil.convertToString(m.get("sourceid")))).collect(Collectors.toList());
        int count = 0;
        int countforActual = 0;
        while (startDate.before(endDate)) {
            // 本周需要开周会且本周周会已开，count+1
            if (this.needWeekMeet(startDate) && this.getMeetingsForWeek(startDate, meetings)) {
                int meetCount = 0;
                meetCount = this.getMeetingNumForWeek(startDate, meetings);
                countforActual += meetCount;
                count++;
            }
            startDate.add(Calendar.WEEK_OF_YEAR, 1);
        }
        return countforActual;
    }
    public int setMeetActualForStatCount(Date start, Date end, String sourceid, List<Map<String, Object>> meetList) {
        // 开始时间（当前周周一）、结束时间（当前周周日）
        Calendar startDate = Calendar.getInstance();
        startDate.setTime(start);
        Calendar endDate = Calendar.getInstance();
        endDate.setTime(end);
        // 获取meetlist中这个项目的信息
        List<Map<String, Object>> meetings = meetList.stream().filter(m -> sourceid.contentEquals(ConvertUtil.convertToString(m.get("sourceid")))).collect(Collectors.toList());
        int count = 0;
        int countforActual = 0;
        while (startDate.before(endDate)) {
            // 本周需要开周会且本周周会已开，count+1
            if (this.needWeekMeet(startDate) && this.getMeetingsForWeek(startDate, meetings)) {
                int meetCount = 0;
                meetCount = this.getMeetingNumForWeek(startDate, meetings);
                countforActual += meetCount;
                count++;
            }
            startDate.add(Calendar.WEEK_OF_YEAR, 1);
        }
        return count;
    }


    /***
     * @description: 获取会议信息通用接口
     * @return
     * @author: houyuhang
     * @date: 2023/03/03
     * @modify:
     */
    public List<Map<String, Object>> queryMeetInfoGeneral(String token, String sourceids) {
        String qry_sourceids = sourceids;
        String qry_sorucetype = MpmSystemConst.MpmMeetParam.SOURCETYPE;
        String qry_soruceapp = MpmSystemConst.MpmMeetParam.SOURCEAPP;
        String qry_state = MpmSystemConst.MpmMeetParam.STATE;
        JSONObject paramap = new JSONObject();
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCETYPE,qry_sorucetype);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCEAPP,qry_soruceapp);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_SOURCEIDS,qry_sourceids);
        paramap.put(MpmSystemConst.MpmMeetParam.QRY_STATE,qry_state);
        String url  = Config.getInstance().getValue("MeetServerUrl", "")+"/meet/meetManage/list";
        String result = HttpRequest.post(url).auth(token).body(paramap.toJSONString()).execute().body();
        Map jsonRes = JSONObject.parseObject(result, Map.class);
        Map<String, Object> resultMap = (Map) jsonRes.get("result");
        List<Map<String, Object>> meetList = (List) resultMap.get("dataList");
        return meetList;
    }
    /***
     * @description: 计算召开率，未开周数，合计行
     * @return
     * @author: houyuhang
     * @date: 2023/03/03
     * @modify:
     */
    public void getMoreMeetStatDetails(List<Map<String, Object>> meetInfo) {
        for (Map<String, Object> meetMap : meetInfo) {
            BigDecimal meetneed = ConvertUtil.convertToBigDecimal(meetMap.get("meetneed"));
            BigDecimal meetactualforcount = ConvertUtil.convertToBigDecimal(meetMap.get("meetactualforcount"));
            meetMap.put("noweekcount", meetneed.subtract(meetactualforcount));
        }
    }
    /**
     * @author: houyuhang
     * @date: 2022-03-03
     * @return
     * @description:计算统计信息
     * @modify:
     */
    public void calculateMeetTotal(List<Map<String, Object>> meetInfo) {
        if (CollectionUtil.isEmpty(meetInfo)) {
            return;
        }
        Set<String> projectkey = meetInfo.get(0).keySet();
        Map<String, Object> totalMap = new HashMap<>();
        String[] noNeedTotal = {"deptcommoncode", "projectmanager", "listid"};
        List<String> noNeedTotalList = new ArrayList<>(Arrays.asList(noNeedTotal));
        for (String key : projectkey) {
            if ("dispdeptcommoncode".equals(key)) {
                totalMap.put(key, "合计");
            } else if (!noNeedTotalList.contains(key)) {
                BigDecimal bigDecimal = new BigDecimal(0);
                for (Map<String, Object> projectEnableMap : meetInfo) {
                    bigDecimal = bigDecimal.add(ConvertUtil.convertToBigDecimal(projectEnableMap.get(key)));
                }
                totalMap.put(key, bigDecimal);
            }
        }
        meetInfo.add(totalMap);
    }
    /***
     * @description: 计算召开率
     * @return
     * @author: houyuhang
     * @date: 2023/03/03
     * @modify:
     */
    public void calculateMeetAverage(List<Map<String, Object>> meetInfo) {
        for (Map<String, Object> meetMap : meetInfo) {
            BigDecimal meetneed = ConvertUtil.convertToBigDecimal(meetMap.get("meetneed"));
            BigDecimal meetactual = ConvertUtil.convertToBigDecimal(meetMap.get("meetactual"));
            if (meetneed.compareTo(BigDecimal.ZERO) == 0) {
                meetMap.put("haveratio", "/");
            } else if (meetactual.compareTo(BigDecimal.ZERO) == 0) {
                meetMap.put("haveratio", "0%");
            } else {
                meetMap.put("haveratio", meetactual.divide(meetneed,4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString() + "%");
            }
        }
    }
    /***
     * @description: 项目来源选择为1个机会点时，立项审批通过后将项目名称反向同步到机会点中
     * @return
     * @author: houyuhang
     * @date: 2023/03/17
     * @modify:
     */
    public void syncProjectNameToChance(MpmProjectEntity mpmProjectEntity, MpmProjectSaleEntity mpmProjectSaleEntity) {
        // 判断是否有其他项目也引用了此机会点，如果存在这种情况return
        String chanceclue = mpmProjectSaleEntity.getChanceclue();
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" projectsource = '{0}' and chanceclue like '%{1}%' ", MpmSystemConst.MpmProjectSource.chance, chanceclue);
        List<MpmProjectSaleEntity> mpmProjectSaleEntities = mpmProjectSaleService.queryByWhere(sql.toString());
        if (mpmProjectSaleEntities.size() > 1) {
            return;
        }
        String projectname = mpmProjectEntity.getProjectname();
        ltcChanceBackboneService.changeNameByMpmProject(projectname, chanceclue, mpmProjectEntity.getProjectmanagercode());
    }
    /***
     * @description: 中标结果日期更新至销售项目的计划完成日期
     * @return
     * @author: houyuhang
     * @date: 2023/03/20
     * @modify:
     */
    public void syncProjectEndDate(List<Map<String, Object>> dateList) {
        // 一个中标信息可能关联多个销售项目，遍历更新
        for (Map<String, Object> dateMap : dateList) {
            // 获取项目编号、同步日期
            String projectcode = ConvertUtil.convertToString(dateMap.get("projectcode"));
            Date enddate = ConvertUtil.convertToDate(dateMap.get("enddate"));
            if (StringUtil.isEmpty(projectcode) || enddate == null) {
                continue;
            }
            // 查询（“产品类招标”、“服务类招标”、“电商招标”）项目
            StringBufferProxy sql = new StringBufferProxy();
            String purchasePattern = MpmSystemConst.PurchasePattern.chanpinBid + "," + MpmSystemConst.PurchasePattern.fuwuBid + "," + MpmSystemConst.PurchasePattern.dianshang;
            sql.appendSingle(" projectcode = '{0}' and purchasepattern in ({1}) ", projectcode, purchasePattern);
            List<Map<String, Object>> projectList = this.queryMapByWhere(sql.toString(), "queryPolymarizationMapByWhere");
            if (CollectionUtil.isEmpty(projectList)) {
                continue;
            }
            Map<String, Object> mpmProjectMap = projectList.get(0);
            // 如果是第一次同步，直接将立项信息中计划结束时间覆盖。如果不是第一次，晚于计划结束时间，进行更新
            String firsttimeflag = ConvertUtil.convertToString(mpmProjectMap.get("bidsyncflag"));
            Map<String, Object> changeMap = new HashMap<>();
            if (StringUtil.isEmpty(firsttimeflag) || "0".equals(firsttimeflag)) {
                changeMap.put("id", ConvertUtil.convertToLong(mpmProjectMap.get("id")));
                changeMap.put("planenddate", enddate);
                changeMap.put("bidsyncflag", 1);
                this.update(changeMap);
            } else {
                if (enddate.compareTo(ConvertUtil.convertToDate(mpmProjectMap.get("planenddate"))) > 0) {
                    changeMap.put("id", ConvertUtil.convertToLong(mpmProjectMap.get("id")));
                    changeMap.put("planenddate", enddate);
                    this.update(changeMap);
                }
            }
        }
    }
    /***
     * @description: 获取会议结束日期与当前日期前一周中更早的日期
     * @return
     * @author: houyuhang
     * @date: 2023/04/06
     * @modify:
     */
    public Date getMeetPreviousDate(Date meetEndDate) {
        // 如果meetenddate为空，赋值为2099-01-01，此时最小日期为当前日期上一周的星期日
        if (meetEndDate == null) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            meetEndDate = sdf.parse(lastDate, new ParsePosition(0));
        }
        // 得到当前日期上一周的星期日,比较此日期与会议结束时间，取最小日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, -7);
        Date nowenddate = ConvertTimeUtil.convertToThisWeekSunday(calendar).getTime();
        return meetEndDate.compareTo(nowenddate) > 0 ? nowenddate : meetEndDate;
    }
    /***
     * @description: 增加四张表字段
     * @return
     * @author: houyuhang
     * @date: 2023/05/29
     * @modify:
     */
    public void setFourPageFields(List<Map<String, Object>> tempList) {
        String temp;
        for (Map<String, Object> mapRow : tempList) {
            if (mapRow.get("deptcommoncode") != null) {
                temp = mapRow.get("deptcommoncode").toString();
                mapRow.put("dispdeptcommoncode", datacodeCache.getValueDynamic("DeptCommonCodeTrack", temp, "code", "name"));
            }
            // 遍历为任务赋值
            for (Map.Entry<String, Object> entry : mapRow.entrySet()) {
                if (entry.getKey().contains("taskst")) {
                    temp = entry.getValue() == null ? "0" : ConvertUtil.convertToString(entry.getValue());
                    mapRow.put(entry.getKey(), datacodeCache.getValueDynamic("MpmSummaryState", temp, "code", "name"));
                }
            }
            if (mapRow.get("ziping1") != null) {
                temp = mapRow.get("ziping1").toString();
                mapRow.put("ziping1", datacodeCache.getValueDynamic("MpmSummaryState", temp, "code", "name"));
            }
            if (mapRow.get("ziping2") != null) {
                temp = mapRow.get("ziping2").toString();
                mapRow.put("ziping2", datacodeCache.getValueDynamic("MpmSummaryState", temp, "code", "name"));
            }
            mapRow.putIfAbsent("baifang1", 0);
            mapRow.putIfAbsent("baifang2", 0);
            // 中标返回金额，未中标返回中标结果
            if (mapRow.get("projectresult") != null) {
                temp = mapRow.get("projectresult").toString();
                if ("1".equals(temp)) {
                    mapRow.put("dispprojectresult", mapRow.get("settlementmoney") + "万元");
                } else {
                    mapRow.put("dispprojectresult", datacodeCache.getValueDynamic("MpmProjectResult", temp, "code", "name"));
                }
            }
            if (mapRow.get("projectstate") != null) {
                if (MpmSystemConst.ProjectState.ExecuteStateCode.equals(ConvertUtil.convertToString(mapRow.get("projectstate")))) {
                    mapRow.put("dispprojectstate", MpmSystemConst.MpmWordProjectState.executeState);
                } else {
                    mapRow.put("dispprojectstate", MpmSystemConst.MpmWordProjectState.finishState);
                }
            }
            // 得到整体任务完成率
            BigDecimal finishTaskCount = ConvertUtil.convertToBigDecimal(mapRow.get("finishtask"));
            BigDecimal allTaskCount = ConvertUtil.convertToBigDecimal(mapRow.get("alltask"));
            mapRow.put("taskratio", this.setBidScoreRatio(finishTaskCount, allTaskCount));
            if (mapRow.get("thisbidlist") != null) {
                temp = mapRow.get("thisbidlist").toString();
                mapRow.put("dispthisbidlist", datacodeCache.getValueDynamic("MpmSummaryFourPageShow", temp, "code", "name"));
            }
            if (mapRow.get("bidmark") != null) {
                temp = mapRow.get("bidmark").toString();
                mapRow.put("dispbidmark", datacodeCache.getValueDynamic("MpmSummaryFourPageShow", temp, "code", "name"));
            }
            if (mapRow.get("smallbidscore") != null) {
                temp = mapRow.get("smallbidscore").toString();
                mapRow.put("dispsmallbidscore", datacodeCache.getValueDynamic("MpmSummaryFourPageShow", temp, "code", "name"));
            }
            if (mapRow.get("expertlist") != null) {
                temp = mapRow.get("expertlist").toString();
                mapRow.put("dispexpertlist", datacodeCache.getValueDynamic("MpmSummaryFourPageShow", temp, "code", "name"));
            }
            if (mapRow.get("projectmanager") != null && mapRow.get("projectmanagercode") != null) {
                mapRow.put("dispprojectmanager", ConvertUtil.convertToString(mapRow.get("projectmanager")) + "[" + ConvertUtil.convertToString(mapRow.get("projectmanagercode")) + "]");
            }
        }
    }
    /***
     * @description: 差距项均制定提分计划
     * @return
     * @author: houyuhang
     * @date: 2023/05/30
     * @modify:
     */
    public void setBidScoreInfo(List<Map<String, Object>> tempList) {
        String projectCodes = tempList.stream().map(map -> ConvertUtil.convertToString(map.get("projectcode")))
                .collect(Collectors.joining("','", "'", "'"));
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" projectcode in ({0}) and times in ('1', '2') and type in ('1', '2') and state = 9 and scoregap > 0 ", projectCodes);
        List<MpmProjectBidScoreEntity> bidEntities = mpmProjectBidScoreService.queryByWhere(sql.toString());
        // 存在差距项的条目
        Map<String, List<MpmProjectBidScoreEntity>> firstResMap = bidEntities.stream().filter(item -> MpmSystemConst.BidScoreTimes.firstTime.equals(item.getTimes())).collect(Collectors.groupingBy(MpmProjectBidScoreEntity::getProjectcode));
        Map<String, List<MpmProjectBidScoreEntity>> secondResMap = bidEntities.stream().filter(item -> MpmSystemConst.BidScoreTimes.secondTime.equals(item.getTimes())).collect(Collectors.groupingBy(MpmProjectBidScoreEntity::getProjectcode));
        // 获取达到目标的数量
        sql.clear();
        sql.appendSingle(" mpmprojectbidscore.projectcode in ({0}) and mpmprojectbidscore.times in ('1', '2') and mpmprojectbidscore.type in ('1', '2') and mpmprojectbidscore.state = 9 and scoregap > 0 and mpmprojectbidscorefeedback.state = 9 and isfinishbidscore = '1' and mpmprojectbidscorefeedback.completionscore = targetscore ", projectCodes);
        List<Map<String, Object>> bidFeedback = mpmProjectBidScoreFeedBackService.queryMapByWhere(sql.toString(), "getBidForSummary");
        // 完成评分细则反馈且反馈得分等于目标得分
        Map<String, List<Map<String, Object>>> firstFeedbackMap = bidFeedback.stream().filter(item -> MpmSystemConst.BidScoreTimes.firstTime.equals(ConvertUtil.convertToString(item.get("times")))).collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.get("projectcode"))));
        Map<String, List<Map<String, Object>>> secondFeedbackMap = bidFeedback.stream().filter(item -> MpmSystemConst.BidScoreTimes.secondTime.equals(ConvertUtil.convertToString(item.get("times")))).collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.get("projectcode"))));
        for (Map<String, Object> mapRow : tempList) {
            String projectcode = ConvertUtil.convertToString(mapRow.get("projectcode"));
            this.setImprovePlan(mapRow, firstResMap.get(projectcode), MpmSystemConst.BidScoreTimes.firstTime);
            this.setImprovePlan(mapRow, secondResMap.get(projectcode), MpmSystemConst.BidScoreTimes.secondTime);
            BigDecimal finishFirst = CollectionUtil.isEmpty(firstFeedbackMap.get(projectcode)) ? BigDecimal.ZERO : BigDecimal.valueOf(firstFeedbackMap.get(projectcode).size());
            BigDecimal allFirst = CollectionUtil.isEmpty(firstResMap.get(projectcode)) ? BigDecimal.ZERO : BigDecimal.valueOf(firstResMap.get(projectcode).size());
            BigDecimal finishSecond = CollectionUtil.isEmpty(secondFeedbackMap.get(projectcode)) ? BigDecimal.ZERO : BigDecimal.valueOf(secondFeedbackMap.get(projectcode).size());
            BigDecimal allSecond = CollectionUtil.isEmpty(secondResMap.get(projectcode)) ? BigDecimal.ZERO : BigDecimal.valueOf(secondResMap.get(projectcode).size());
            mapRow.put("dacheng1", this.setBidScoreRatio(finishFirst, allFirst));
            mapRow.put("dacheng2", this.setBidScoreRatio(finishSecond, allSecond));
        }
    }
    /***
     * @description: 差距项均制定提分计划
     * @return
     * @author: houyuhang
     * @date: 2023/05/30
     * @modify:
     */
    public void setImprovePlan(Map<String, Object> mapRow, List<MpmProjectBidScoreEntity> bidList, String times) {
        if (CollectionUtil.isEmpty(bidList)) {
            return;
        }
        int havePlan = (int) bidList.stream().filter(item -> !StringUtil.isEmpty(item.getScoringplan()) && !"/".equals(item.getScoringplan()) && !"无".equals(item.getScoringplan())).count();
        if (havePlan == bidList.size()) {
            mapRow.put("tifen" + times, MpmSystemConst.MpmSummaryState.four);
        } else if (havePlan > 0) {
            mapRow.put("tifen" + times, MpmSystemConst.MpmSummaryState.three);
        } else {
            mapRow.put("tifen" + times, MpmSystemConst.MpmSummaryState.two);
        }
        mapRow.put("tifen" + times, datacodeCache.getValueDynamic("MpmSummaryState", ConvertUtil.convertToString(mapRow.get("tifen" + times)), "code", "name"));
    }
    /***
     * @description: 差距追赶目标达成率
     * @return
     * @author: houyuhang
     * @date: 2023/05/30
     * @modify:
     */
    public String setBidScoreRatio(BigDecimal on, BigDecimal under) {
        if (under.compareTo(BigDecimal.ZERO) == 0) {
            return "/";
        } else if (on.compareTo(BigDecimal.ZERO) == 0) {
            return "0%";
        } else {
            return on.divide(under,4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString() + "%";
        }
    }
    /***
     * @description: 获取项目累计督办次数
     * @return
     * @author: houyuhang
     * @date: 2023/05/30
     * @modify:
     */
    public void setSuperviseInfo(List<Map<String, Object>> tempList) {
        String projectCodes = tempList.stream().map(map -> ConvertUtil.convertToString(map.get("projectcode")))
                .collect(Collectors.joining("','", "'", "'"));
        StringBufferProxy sql = new StringBufferProxy();
        // 查询督办表获取所有项目的督办情况
        sql.appendSingle("projectcode in ({0})", projectCodes);
        List<Map<String, Object>> superviseMap = mpmProjectSuperviseService.queryMapByWhere(sql.toString());
        List<Map<String, Object>> filterSupervise = mpmProjectPolymerizationService.handleSuperviseListForList(superviseMap);
        Map<String, List<Map<String, Object>>> filterSuperviseMap = filterSupervise.stream().collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.get("projectcode"))));
        for (Map<String, Object> mapRow : tempList) {
            String projectcode = ConvertUtil.convertToString(mapRow.get("projectcode"));
            if (CollectionUtil.isEmpty(filterSuperviseMap.get(projectcode))) {
                mapRow.put("supervisecount", 0);
            } else {
                mapRow.put("supervisecount", filterSuperviseMap.get(projectcode).size());
            }
        }
    }
    /***
     * @description: 获取项目报表
     * @return
     * @author: houyuhang
     * @date: 2023/05/30
     * @modify:
     */
    public Page queryFourPageForm(Map<String, Object> paraMap) {
        Query query = new Query(paraMap);
        int begincount=query.getCurrentPage()*query.getPageSize()-query.getPageSize();
        paraMap.put("begincount",begincount);
        paraMap.put("pagesize", query.getPageSize());
        paraMap.put("sidx", query.getSidx());
        paraMap.put("sord", query.getSord());
        // 查询任务
        List<String> tasklist = Arrays.asList(ParameterCache.getValue("MpmFourPageTask").split(","));
        paraMap.put("tasklist", tasklist);
        int totalCount = this.queryMap(paraMap, "queryFourPageForm").size();
        List<Map<String, Object>> tempList = null;
        if (query.getPageSize() > 0) {
            tempList = this.queryMapForPage(paraMap, "queryFourPageFormForPage");
        } else
            tempList = this.queryMap(paraMap, "queryFourPageForm");
        // 差距项均制定提分计划
        List<List<Map<String, Object>>> splitList = mpmProjectTaskService.splitInList(tempList);
        for (List<Map<String, Object>> resList : splitList) {
            this.setBidScoreInfo(resList);
            this.setSuperviseInfo(resList);
            mpmProjectPolymerizationService.setSignInfo(resList);
        }
        // 编码转换
        mpmProjectService.setFourPageFields(tempList);
        Page page = new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
        return page;
    }
}
